我有一个针对接口运行的assembledLambda函数。不幸的是,该接口只是一个标记接口,实类型是在运行时动态生成的,并且具有我要对其进行分组的属性。
下面是一些示例代码:
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; }
}
在编译lambda表达式时,它将引发以下异常:
System.InvalidCastException:'无法转换类型的对象 'System.Func`2 [ConsoleApp12.DynamicGeneratedModelClass,System.Object]' 输入 “ System.Func`2 [ConsoleApp12.IDynamicGeneratedModelClass,System.Object]”。
能否请您提示我我在做什么错以及如何解决?
答案 0 :(得分:3)
Func<T, TResult>
委托的第一个通用参数声明为contravariant(in
),这意味着您可以将派生参数较少的委托分配给派生参数较多的委托,但是反之亦然(换句话说,您可以将Func<IDynamicGeneratedModelClass,Object>
强制转换为Func<DynamicGeneratedModelClass,Object>
,但是不能将Func<DynamicGeneratedModelClass,Object>
强制强制转换为Func<IDynamicGeneratedModelClass,Object>
)。
为避免此问题,您现在生成的不是lambda表达式:
// lambda has "wrong" type Func<DynamicGeneratedModelClass, object>
(DynamicGeneratedModelClass item) => item.SomeProperty
生成与此等效的lambda:
// lambda now has "correct" type Func<IDynamicGeneratedModelClass, object>
(IDynamicGeneratedModelClass item) => ((DynamicGeneratedModelClass)item).SomeProperty
我对您用来生成lambda的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);