【问题标题】:How to create a lambda expression from a type object with LINQ?如何使用 LINQ 从类型对象创建 lambda 表达式?
【发布时间】:2012-06-18 13:31:30
【问题描述】:

我正在尝试使用 LINQ 表达式加速反射 -> SetValue。

我的问题是这个方法:

public void SetValue<T>(T obj)
{
    FieldInfo field = typeof(T).GetField("Title", BindingFlags.Instance |
                                                  BindingFlags.Public |
                                                  BindingFlags.IgnoreCase);

    ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
    ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value");

    // Expression.Property can be used here as well
    MemberExpression fieldExp = Expression.Field(targetExp, field);
    BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp);

    var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile();

    setter(obj, "Hello World");

    //Console.WriteLine(obj.title);
}

我这样称呼:

var ii = new Controllers.SearchController.InstantItem();

SetValue<Controllers.SearchController.InstantItem>(ii);

问题出在这一行:

var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile();

由于 Action 使用泛型,我无法将字符串替换为 field.FieldType...

有没有可能我可以做到这一点,而不必编写switch(field.FieldType) 声明,并为每种可能的类型放置一个通用方法,这会浪费很多时间?

【问题讨论】:

  • 编译动态方法比每次都使用反射要慢得多。我认为您需要缓存设置器。
  • @usr: 是的,但我可以担心以后缓存它。现在我需要先创建它。

标签: c# .net linq generics linq-expressions


【解决方案1】:

可能是这样的

action = FormAction(fieldInfo);
action(obj,valueToSet);

当然需要将动作缓存在字典中。

static Action<object, object> FormAction(FieldInfo fieldInfo)
{
    ParameterExpression obj = Expression.Parameter(typeof(object), fieldInfo.Name);
    ParameterExpression value = Expression.Parameter(typeof(object));

    MemberExpression fieldExp = Expression.Field(Expression.Convert(obj, fieldInfo.DeclaringType), fieldInfo.Name);
    BinaryExpression assignExp = Expression.Assign(fieldExp, Expression.Convert(value, fieldInfo.FieldType));

    return Expression.Lambda<Action<object, object>>(assignExp, obj, value).Compile();
}

【讨论】:

  • 我试过了,但错过了 Expression.Convert。很好,工作 - 谢谢!
【解决方案2】:

使参数 ob 类型对象并在内部将 lambda 转换为正确的字段类型。

或者,在运行时动态构造委托类型(Action)。

或者,您可以如下定义 SetValue:

SetValue<TObject, TProperty>

这将使该方法对属性类型具有通用性。

编辑:听起来选项 1 最适合您。您需要将参数类型更改为typeof(object) 并添加演员表:

valueExp = Expression.Convert(valueExp, field.FieldType)

并且您需要使用Action&lt;T, object&gt; 作为委托类型。

【讨论】:

  • 我知道。但是如何!至于 SetValue:然后我会在编译时再次需要字段/属性类型,这是我不能拥有的,因为每个字段的类型都不同。同样的问题,只是没有 Lambda 表达式。
  • 好的,我添加了一些说明。这就是它的全部内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多