在运行时检查属性类型,并为Generic lambda表达式参数T提供相同的类型

时间:2012-11-06 10:36:58

标签: c# .net linq generics lambda

我有一些代码片段,如下所示:

想要通过在运行时检查类型来解决此问题。

PropertyInfo pi = type.GetProperty("propertyName");

var expression = new Object(); // this give me error after expression runs!

    // Want to resolve this conditation by checking the type at runtime.
    if (pi.PropertyType == typeof(DateTime))
            {
               // Want to pass the generic type parameter which has a same type created at runtime by identifying the property type.
                expression = BuildExpression<T, DateTime>(data, group.Member);
            }

private Func<T, V> BuildExpression<T, V>(IEnumerable<T> items, string propertyName)
    {
      Type type = typeof(T);
      PropertyInfo pi = type.GetProperty(propertyName);
      Type PropertyType = pi.DeclaringType;
      var parameter = Expression.Parameter(typeof(T), propertyName);
      var cast = Expression.TypeAs(parameter, pi.DeclaringType);
      var getterBody = Expression.Property(cast, pi);
      var exp = Expression.Lambda<Func<T, V>>(getterBody, parameter);
      return exp.Compile();
    }

问题: 我必须在类型I上写条件,我必须通过反射检查属性的类型,然后必须构建表达式。

我想要的是什么: 我想检查运行时的属性类型,并希望构建该类型的运行时通用参数,该参数与属性类型相同。

基本上我想删除类型检查上的If条件 和我想要的是,代码应该automatically detect the property type并在Generic parameter argument中传递相同的类型,所以我不必检查具有If条件的所有类型。与string, decimal, double etc..

一样

您能不能让我知道该决议,因为我想在运行时检查property类型,并希望使用与属性相同的类型创建Generic parameter type

1 个答案:

答案 0 :(得分:1)

有一个返回Func<T,V>(对象T和成员类型V)的方法是有问题的,因为在运行时你无法对它做任何有用的事情。如果在编译时不知道TV,则无法将其分配给类型代理,并且使用DynamicInvoke不是一个好主意。坦率地说,你最好建立一个Func<object,object>,并在运行时只处理object。反思和泛型不能很好地混合。

private static Func<object, object> BuildExpression(
    Type type, string propertyName)
{
    var parameter = Expression.Parameter(typeof(object));
    var body = Expression.TypeAs(Expression.PropertyOrField(Expression.TypeAs(
        parameter, type), propertyName), typeof(object));
    return Expression.Lambda<Func<object, object>>(body, parameter).Compile();
}

但是,此时你可以,IMO,只需切换到FastMember这样的库,并使用基于名称的访问:

var accessor = TypeAccessor.Create(type);
var obj = ...
var propVal = accessor[obj, propertyName];