Как сгруппировать лямбда-функцию с типом, сгенерированным во время выполнения - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть функция compiledLambda, которая работает с интерфейсом. К сожалению, интерфейс - это просто маркерный интерфейс, и реальный тип генерируется на лету во время выполнения и обладает свойствами, для которых я хочу выполнить группировку.

Вот пример кода:

class Program
{
    static void Main(string[] args)
    {
        // Just an example assignment: In the real life scenario the dynamic generated class is created during runtime. 
        IEnumerable<IDynamicGeneratedModelClass> list = GetDataFromService();

        // get the 'real' type from the list
        LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(list.First().GetType(), typeof(object), "SomeProperty");
        Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpression.Compile();

        // Expected result: Group list on "SomeProp"
        var result = list.GroupBy(compiledLambdaFunction);
    }

    private static IList<IDynamicGeneratedModelClass> GetDataFromService()
    {
        return new List<IDynamicGeneratedModelClass> {  
            new DynamicGeneratedModelClass("Class1"),
            new DynamicGeneratedModelClass("Class2")
        };
    }
}

public interface IDynamicGeneratedModelClass
{}

public class DynamicGeneratedModelClass : IDynamicGeneratedModelClass
{
    public DynamicGeneratedModelClass(string someProperty)
    {
        SomeProperty = someProperty;
    }

    public string SomeProperty { get; }
}

Когда лямбда-выражение компилируется, оно выдает следующее исключение:

System.InvalidCastException: 'Невозможно привести объект типа 'System.Func`2 [ConsoleApp12.DynamicGeneratedModelClass, System.Object] печатать 'System.Func`2 [ConsoleApp12.IDynamicGeneratedModelClass, System.Object]'. '

Не могли бы вы дать мне подсказку, что я делаю неправильно и как это исправить?

1 Ответ

0 голосов
/ 04 сентября 2018

Первый универсальный параметр делегата Func<T, TResult> объявлен как контравариантный (in), что означает, что вы можете назначить делегат с менее производным параметром делегату с более производным параметром, но не вице наоборот (другими словами, вы можете разыграть Func<IDynamicGeneratedModelClass,Object> до Func<DynamicGeneratedModelClass,Object>, но не можете разыграть Func<DynamicGeneratedModelClass,Object> до Func<IDynamicGeneratedModelClass,Object>).

Чтобы избежать этой проблемы, вместо лямбда-выражения, которое вы генерируете сейчас:

// lambda has "wrong" type Func<DynamicGeneratedModelClass, object>
(DynamicGeneratedModelClass item) => item.SomeProperty

генерирует лямбда-эквивалент, эквивалентный этому:

// lambda now has "correct" type Func<IDynamicGeneratedModelClass, object>
(IDynamicGeneratedModelClass item) => ((DynamicGeneratedModelClass)item).SomeProperty

Я не знаком с библиотекой DynamicExpression, которую вы использовали для создания лямбды, но это легко сделать с помощью System.Linq.Expression классов:

var itemType = list.First().GetType();
var propertyName = "SomeProperty";
var parameterExpr = Expression.Parameter(typeof(IDynamicGeneratedModelClass));
var castExpr = Expression.Convert(parameterExpr, itemType);
var propExpr = Expression.Property(castExpr, propertyName);
var lambdaExpr = Expression.Lambda(propExpr, parameterExpr);

// Compiled lambda is now of type Func<IDynamicGeneratedModelClass, object>
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpr.Compile();

var result = list.GroupBy(compiledLambdaFunction);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...