通过传递Expression <func <t,object =“”>&gt; </func <t,>使用反射来调用方法

时间:2013-07-10 18:18:33

标签: c# generics reflection .net-4.0 expression

关注my own question我发现我现在需要通过将Expression<Func<T, object>>传递给我的方法来调用相同的服务和相同的方法。这是方法定义:

IList<T> List(params Expression<Func<T, object>>[] includeProperties);

以下是我现在的代码:

  //Get generic type
  var entityRelationType = typeof(Applicant).Assembly.GetType(string.Format("Permet.BackEnd.ETL.Domain.Models.{0}", tableRelation.RelationEntityName));

  //create service that will receive the generic type
  var definitionIService = typeof(IService<>).MakeGenericType(entityRelationType);

  //instantiate the service using Unity (todo: fix singleton)
  var serviceInstance = UnitySingleton.Container.Resolve(definitionIService, "");

  //create the argument for the method that we invoke
  var paramsType =
            typeof(Expression<>).MakeGenericType(typeof(Func<,>)
            .MakeGenericType(entityRelationType, typeof(object))).MakeArrayType();


#region Get Dynamic Data
   ParameterExpression relationParameter = Expression.Parameter(entityRelationType, "");

   //build the parameter that we want to pass to the method (Expression<Func<T, object>>
   var include =
         Expression.Lambda(
                    Expression.Property(relationParameter,  tableRelation.NaviguationProprietyName),
                    relationParameter
                    );

dynamic datas = constructedIService
                            .GetMethod("List", new Type[] { paramsType }).Invoke(serviceInstance, new object[] { include });

include成功创建了我的lambda表达式(Param_0 =&gt; Param_0.Groupings),我认为它是我的Expression<Func<T, object>>。但是,由于Param_0.Groupings实际上是一个IList,我得到一个例外:

  

类型为'System.Linq.Expressions.Expression 1[System.Func的对象2 [Permet.BackEnd.ETL.Domain.Models.CLLI,System.Collections.Generic.IList 1[Permet.BackEnd.ETL.Domain.Models.Grouping]]]' cannot be converted to type 'System.Linq.Expressions.Expression 1 [System.Func `2 [Permet.BackEnd.ETL.Domain.Models.CLLI,System.Object的] []”。

这基本上意味着我的Expression<Func<CLLI, IList<Grouping>>>无法在我需要Expression<Func<CLLI, object>>的方法中使用。

如果我直接打电话给我的服务:

IService<CLLI> clliService = new Service<CLLI>();
clliService.List(clli => clli.Groupings);

有效。

我该如何解决这个问题? IList不是一个对象吗?

1 个答案:

答案 0 :(得分:1)

问题是Expression<T>是不变的,因此即使您有一个类型T可以分配到U类型,但这并不意味着Expression<T>可以分配到Expression<U>。在您的情况下,TFunc<CLI, IList<Grouping>>UFunc<CLLI, object>

我认为唯一的解决方案是创建一个函数来将一个给定的表达式包装在Expression<Func<T, object>>中,该函数委托给内部表达式并将结果强制转换为object

public static Expression<Func<T, object>> ConvertResult<T, TOut>(Expression<Func<T, TOut>> expr)
{
    var paramExpr = Expression.Parameter(typeof(T));
    var invokeExpr = Expression.Invoke(expr, paramExpr);
    var castExpr = Expression.Convert(invokeExpr, typeof(object));

    return Expression.Lambda<Func<T, object>>(castExpr, paramExpr);
}