2013-08-15 1 views
1

Моя цель здесь заключается в создании метода SortRecords, который принимает параметры IEnumerable<T> и PropertyInfo. IEnumerable<T> - это список записей. PropertyInfo является собственностью T. При вызове SortRecords следует использовать метод Enumerable.SortBy<T, typeof Property> с x => x.Property. Обратите внимание, что Enumerable.SortBy имеет два общих параметра. Кроме того, отражение не может быть использовано внутри выражения лямбда, потому что (а) оно медленное и (б) оно не будет работать с Entity Framework.Использование DynamicMethod для вызова метода с общими параметрами?

Я написал код, но я продолжаю видеть сообщение об ошибке Operation could destabilize the runtime. Вот то, что мой код выглядит

for (int i = 0; i < NumberOfSorts; i++) 
     { 
      string propertyName = PropertyNames[ColumnSortOrder[i]]; 
      PropertyInfo property = typeof(T).GetProperties().Single(p => p.Name == propertyName);    

      Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>> sortingFunction = GetFunctionToSortRecords<T>(filteredRecords, property); 
      sortedRecords = GetFunctionToSortRecords<T>(filteredRecords, property)(filteredRecords, property); 
     } 

конца первого фрагмент код

определение метод следует

delegate IEnumerable<T> GetFunctionToSortRecordsDelegate<T>(IEnumerable<T> records, PropertyInfo propertyToSortOn); 
public static Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>> GetFunctionToSortRecords<T>(IEnumerable<T> records, PropertyInfo propertyToSortOn) 
    { 
     Type propertyType = propertyToSortOn.GetType(); 

     DynamicMethod method = new DynamicMethod("SortRecords", typeof(IEnumerable<T>), new Type[] { typeof(IEnumerable<T>), typeof(PropertyInfo) });    
     ILGenerator generator = method.GetILGenerator();    

     MethodInfo GetPropertyValue = propertyToSortOn.GetGetMethod(); 
     MethodInfo GetDefaultKeySelectorForProperty = typeof(DataTablesSorting).GetMethod("GetDefaultKeySelectorForProperty")                           
      .MakeGenericMethod(new Type[] {typeof(T), propertyToSortOn.PropertyType });    

     MethodInfo EnumerableOrderBy = typeof(Enumerable).GetMethods() 
      .Single(m => m.Name == "OrderBy" && m.GetParameters().Count()==3); 

     // Get the default key selector for the property passed in.    
     generator.Emit(OpCodes.Ldarg_1); // property 
     generator.Emit(OpCodes.Call, GetDefaultKeySelectorForProperty); 

     // Save the default key selector at location 0 
     generator.Emit(OpCodes.Stloc_0); 

     generator.Emit(OpCodes.Ldarg_0); // records 
     generator.Emit(OpCodes.Ldloc_0); // default key selector 
     generator.Emit(OpCodes.Call, EnumerableOrderBy); 
     generator.Emit(OpCodes.Ret); 

     return ((GetFunctionToSortRecordsDelegate<T>)(method.CreateDelegate(typeof(GetFunctionToSortRecordsDelegate<T>)))).Invoke; 
    } 

    delegate TKey GetDefaultKeySelectorForPropertyDelegate<T, TKey>(T t); 
    public static Func<T, TKey> GetDefaultKeySelectorForProperty<T, TKey>(PropertyInfo property) 
    { 
     DynamicMethod method = new DynamicMethod("GetKeySelector", typeof(TKey), new Type[] { typeof(T) }); 
     ILGenerator generator = method.GetILGenerator(); 

     MethodInfo GetPropertyValue = property.GetGetMethod(); 
     generator.Emit(OpCodes.Ldarg_0); 
     generator.Emit(OpCodes.Callvirt, GetPropertyValue); 
     generator.Emit(OpCodes.Ret); 

     return ((GetDefaultKeySelectorForPropertyDelegate<T, TKey>)(method.CreateDelegate(typeof(GetDefaultKeySelectorForPropertyDelegate<T, TKey>)))).Invoke; 
    } 

Я думаю, что этот вопрос может быть связан: DynamicMethod with generic type parameters

ответ

0

Я не использовал DynamicMethod себе вот так, но я подозреваю, что вам просто нужно MakeGenericMethod на этом EnumerableOrderBy так же, как вы 're уже делает для GetDefaultKeySelectorForProperty. На данный момент вы пытаетесь вызвать общий метод без указания аргументов типа.

Так что-то вроде:

MethodInfo EnumerableOrderBy = typeof(Enumerable).GetMethods() 
    .Single(m => m.Name == "OrderBy" && m.GetParameters().Count() == 3) 
    .MakeGenericMethod(typeof(T), propertyToSortOn.PropertyType); 

(. MakeGenericMethod использует массив параметров, так что вам не нужно явно построить Type[] пройти в)

(Если вам нужно работать с Entity Framework, я подумал, что вы бы смотрели на Queryable, а не на Enumerable и строили деревья выражений вместо делегатов, но это другое дело.)

+0

Вы, несомненно, сделали важное замечание, но даже когда я применяю предложенное изменение, я все равно получаю сообщение об ошибке «Операция может дестабилизировать время выполнения». –

+0

@ DanielAllenLangdon: В какой момент? Здесь поможет короткий, но полный пример - если вы можете воспроизвести его с более коротким блоком IL (например, передать делегату заказа), который тоже поможет. –

+0

Я попытался переписать код с помощью отражения и обнаружил, что мне нужен двухпараметрический метод 'OrderBy'. Я думаю, что это определенно одна проблема, но я все еще получаю то же сообщение об ошибке при попытке использовать Dynamic Method. Я думаю, что, возможно, решение может состоять в том, чтобы чисто обернуть общий метод OrderBy в методе, который использует динамический метод и вызывать это ... –

0

Я предпочитаю использовать Expressio ns для этой проблемы. Вот пример, который должен сработать для вас.

public static Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>> GetFunctionToSortRecords<T>(IEnumerable<T> records, PropertyInfo property) 
    { 
     var propertyExpression = GetExpressionForProperty<T>(property); 
     var method = typeof(TheCurrentClass).GetMethod("InternalGetFunctionToSortRecords", BindingFlags.NonPublic | BindingFlags.Static); 

     return (Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>>)method.MakeGenericMethod(typeof(T), property.PropertyType).Invoke(null, new object[] { propertyExpression }); 
    } 

    private static Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>> InternalGetFunctionToSortRecords<T, TProp>(Expression propertyExpression) 
    { 
     var lambdaExpression = propertyExpression as LambdaExpression; 
     Func<T, TProp> keySelector = (Func<T, TProp>)lambdaExpression.Compile(); 
     Func<IEnumerable<T>, PropertyInfo, IEnumerable<T>> sorter = (x, y) => x.OrderBy(keySelector); 

     return sorter.Invoke; 
    } 

    private static Expression GetExpressionForProperty<T>(PropertyInfo property) 
    { 
     var parameter = Expression.Parameter(typeof(T)); 
     var propertyExpression = Expression.Property(parameter, property); 
     var lambdaExpression = Expression.Lambda(propertyExpression, parameter); 

     return lambdaExpression; 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^