【问题标题】:How can I build an expression that compiles to a Func<T>?如何构建编译为 Func<T> 的表达式?
【发布时间】:2015-07-08 19:22:05
【问题描述】:

假设我有一个返回 T 的静态方法,例如:

T myT = MyClass.Create(type); // type is System.Type

然后我希望能够构建和编译一个表达式,这样我就可以拥有一个Func&lt;T&gt;,但我不知道该怎么做。

我可以为 Constant 构建它:

Func<T> result = Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile()

但是对于MyClass.Create(type),我被卡住了。

Func<T> result = ....?

【问题讨论】:

  • Expression.Call?你试过什么?
  • 做得很好:-)

标签: c# .net expression expression-trees


【解决方案1】:

感谢usr 的提示,我设法使用Expression.Call 做到了:

public static class MyClass
{
    public static string GetTime() 
    {
        return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff");
    }

    public static string GetName(Type type)
    {
        return type.Name;
    }
}

然后:

// Calls static method GetTime with no args
var mCallGetTime = Expression.Call(typeof(MyClass), "GetTime", null);
Func<string> resultNoArg = Expression.Lambda<Func<string>>(mCallGetTime).Compile();

// The input param for GetName which is of type Type
var paramExp = Expression.Parameter(typeof(Type));

// Calls static method GetName passing in the param
var mCallGetName = Expression.Call(typeof(MyClass), "GetName", null, paramExp);
Func<Type, string> resultWithArg = Expression.Lambda<Func<Type, string>>(mCallGetName, paramExp).Compile();

// You can then call them like so... Print() just prints the string
resultNoArg().Print();
resultWithArg(typeof(string)).Print();
resultWithArg(typeof(int)).Print();

或者,而不是:

var mCallGetTime = Expression.Call(typeof(MyClass), "GetTime", null);

我们可以编写Expression.Call 使用:

// Get the method info for GetTime (note the Type[0] signifying no args taken by GetTime);
var methodInfo = typeof(MyClass).GetMethod("GetTime", new Type[0]);
var mCallGetTime = Expression.Call(methodInfo);

GetName 也是如此:

// Get the method info for GetName (note the new[] {typeof(Type)} signifying the arg taken by GetName
var getNameMethodInfo = typeof(MyClass).GetMethod("GetName", new[] { typeof(Type)});
var mCallGetName = Expression.Call(getNameMethodInfo, paramExp);

【讨论】:

  • 如果你直接编译一个表达式,那么大多数时候你不需要它,你的第一行有什么问题?
【解决方案2】:

您的答案的另一种选择是创建一个完全通用的方法,该方法将为任何类型的任何通用静态方法构造一个 Func&lt;T&gt;

public Func<T> BuildGenericStaticFunc<T>()
{
    var type = typeof(T);
    return Expression.Lambda<Func<T>>(
        Expression
            .Call(
                type.GetMethod("Create", BindingFlags.Static | BindingFlags.Public)
                    .MakeGenericMethod(type),
                Expression.Constant(type)
                ))
            .Compile();
}

var result = BuildGenericStaticFunc<MyClass>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    相关资源
    最近更新 更多