c# - c#中的表达式和委托(delegate)

标签 c# dynamic delegates lambda expression

我有以下代码是伪代码。 我想让这个函数可以接受一个 Expresstion 类型,编译这个表达式并用适当的参数调用它。

public static void f<T>(Expression<T> exp, params dynamic[] d)
{
    Console.WriteLine("begin");
    exp.Compile().Invoke(d[0],d[1].....);//this is pseudo-code

    Console.WriteLine("end");
}

我确定 T 是一个 Action 类型。 (T 可以是 ActionAction<int> 等)。参数d是一个动态类型的数组,发送给invoke。

但我不知道如何完成代码。我敢肯定,实现起来并不容易。也许在 c# 中不是这样

最佳答案

您不能使用 Invoke除非你知道确切的签名。但是,您可以使用 DynamicInvoke ,例如:

((Delegate)exp.Compile()).DynamicInvoke(d);

请注意 dynamic以上没有任何意义 - d也可以是object[] .

另一种稍微复杂一些的方法 - 将其编译为 Func<object[]> , 并重新编写表达式 ( ExpressionVisitor ) 以将“参数 n” (来自原始 exp ) 替换为 p[n] , 其中p是单ParameterExpressionnConstantExpressionn . 如果您要存储并积极地重新使用已编译的 lambda,这可能是有利的。但在您的特定场景中,您是在每次调用时进行编译,因此这没有任何好处。

这是一个例子,但这主要是为了以后有类似场景的读者,但是编译委托(delegate)被重新使用;这种重写的“优势”是它避免了 Delegate.DynamicInvoke 的性能影响。 , 同时保留 object[] => object Delegate.DynamicInvoke的签名;但这只有在委托(delegate)被多次使用时才有用。目前(每次调用编译)这里的大部分“工作”将在表达式编译和 JIT 编译中进行。

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
static class Program {
    static void Main() {
        Expression<Func<int, float, double>> exp = (i, f) => i * f;
        var func = CompileToBasicType(exp);

        object[] args = { 3, 2.3F };
        object result = func(args); // 6.9 (double)
    }

    static Func<object[], object> CompileToBasicType(LambdaExpression exp) {
        ParameterExpression arg =
            Expression.Parameter(typeof(object[]), "args");
        Dictionary<Expression, Expression> lookup =
            new Dictionary<Expression, Expression>();
        int i = 0;
        foreach (var p in exp.Parameters) {
            lookup.Add(p, Expression.Convert(Expression.ArrayIndex(
                arg, Expression.Constant(i++)), p.Type));
        }
        var body = Expression.Convert(
            new ReplaceVisitor(lookup).Visit(exp.Body), typeof(object));
        return Expression.Lambda<Func<object[], object>>(body, arg).Compile();
    }
    class ReplaceVisitor : ExpressionVisitor {
        private readonly Dictionary<Expression, Expression> lookup;
        public ReplaceVisitor(Dictionary<Expression, Expression> lookup) {
            if (lookup == null) throw new ArgumentNullException("lookup");
            this.lookup= lookup;
        }
        public override Expression Visit(Expression node) {
            Expression found;
            return lookup.TryGetValue(node, out found) ? found
                : base.Visit(node);
        }
    }
}

关于c# - c#中的表达式和委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16663567/

相关文章:

c# - Multi-Tenancy Azure AD 身份验证权限错误

excel - Excel 中的动态数据验证(非 VBA!)

javascript - JS/jQuery - 根据用户输入显示结果

c++ - GLEW + cmake 链接失败 "undefined reference to symbol glDrawElements"+ "DSO missing from command line"

c# - 委托(delegate)会导致内存泄漏吗? GC.TotalMemory(true) 似乎表明如此

ios - 如何设置一个简单的委托(delegate)来在两个 View Controller 之间进行通信?

c# - 将 DBnull 存储在数据库中,用于接受 null 的日期列

c# - 预加载多对多 - EF Core

iphone - -[__NSArrayI isEqualToString :]: message sent to deallocated instance

c# - 寻找一个离线库来格式化 HTML,我可以将其与 .NET 代码一起使用