【问题标题】:Expression tree : avoid DynamicInvoke表达式树:避免 DynamicInvoke
【发布时间】:2012-11-28 20:28:24
【问题描述】:

我在运行时使用表达式树来构建委托:

Type type = GetType();
ParameterExpression parameterType = Expression.Parameter(type);
...
Delegate delegate = Expression.Lambda(*something*, parameterType).Compile();

我在编译时不知道 GetType() 方法返回的类型。是否可以在不使用昂贵的 DynamicInvoke() 方法的情况下调用我的委托?

编辑:

在我的应用程序中,我有一个基础抽象类:

public abstract class Frame
{
    public string RawContent { get; set; }

    // ...
}

在运行时,应用程序将使用一些继承 Frame 的对象;这些对象的类型在编译时是未知的,因为它们将使用 MEF(插件)加载。应用程序的目标是过滤带有错误数据的对象:例如,如果程序必须处理像这样的类的某些对象:

public class Frame01 : Frame
{
    public int Counter6hours { get; set; }

    public int DeltaCounter6hours { get; set; }
}

我希望我的用户能够在应用程序的配置文件中编写如下内容:

<filtersSection>
    <filters>
            <filter class="Frame01" expression="Counter6hours < 0" />
            <filter class="Frame01" expression="DeltaCounter6hours > 2500" />
    </filters>
<filtersSection>

我设法创建了一个表达式树并将其编译为每个过滤器的委托。但是我不能将它转换为 Func 因为我在编译时不知道 Frame01 类型......所以,目前,我使用我的委托的 DynamicInvoke() 方法,它以后期绑定的方式调用底层方法。应用程序必须处理大量对象,而且我担心会出现性能问题……因此,在这个示例中,我尝试以编程方式构建一个 Func 对象,但我不确定这是否可行。

PS : 请原谅我的英语不好...

【问题讨论】:

  • 能不能不直接把返回类型设为object
  • @leppie :生成的委托是一个方法,它接受一个对象(在编译时未知)并返回一个布尔值。你的意思是我应该尝试将我的委托转换为 Func??, object> ?
  • @schglurps - 听起来您想将其转换为 Func&lt;object, bool&gt;
  • @leppie :我刚刚尝试将我的委托转换为 Func,但出现运行时错误。你知道以编程方式构建这样一个对象的方法吗?
  • 我真的不明白你想要什么。我在您的代码中看不到任何与Func&lt;object, bool&gt; 相关的内容,您能解决这个问题吗?为什么你有正确类型的对象,但你需要将其视为object?你不能使用泛型吗?你能解释一下为什么你要这样做吗?

标签: c# delegates expression-trees


【解决方案1】:

我仍然不完全清楚这就是你想要的,但我认为你所需要的只是一个转换:你的表达式将有一个Frame 类型的参数,将它转换为Frame01,然后运行你的过滤器那个。

在代码中:

var type = typeof(Frame01);

var param = Expression.Parameter(typeof(Frame));
var casted = Expression.Convert(param, type);

// this part will be dynamic in your actual code
var condition = Expression.LessThan(
    Expression.Property(casted, "Counter6hours"), Expression.Constant(0));

var result = Expression.Lambda<Func<Frame, bool>>(condition, param)
    .Compile();

这样,以下测试通过:

Assert.IsTrue(result(new Frame01 { Counter6hours = -1 }));
Assert.IsFalse(result(new Frame01 { Counter6hours = 1 }));
Assert.Throws<InvalidCastException>(() => result(new Frame02()));

【讨论】:

  • 好的,我终于明白你的意思了!事实上,直到您收到 Expression.Convert() 函数存在的消息,我才注意到。有了这个,我终于可以避免使用 DynamicInvoke() 方法。谢谢您的帮助 !还有你的耐心!
【解决方案2】:

从您的 cmets 中,您希望得到一个 Func&lt;object, bool&gt;

因此,您必须使用object 类型的参数来构建表达式树

这样的事情会起作用:

var p = Expression.Parameter(typeof(object));
var c = Expression.Constant(true);
var lambda = Expression.Lambda(c,p);
var fn = ( Func<object, bool> ) lambda.Compile();

然后:

bool b = fn( ...some object... );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-04
    • 2011-06-12
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    • 2016-07-17
    • 1970-01-01
    相关资源
    最近更新 更多