动态生成 属性 和空参数的表达式

Dynamically generate expression of property and empty argument

注意:请注意,这不是重复的。

我需要创建以下 Lambda 表达式:

() => model.property

模型及其 属性 将在运行时确定。我想要一个接受模型和 属性 并生成表达式的函数:

public object GenerateLambda(object model, string property) 
{

}

如果可能的话,我不希望函数是通用的。 但我认为我遇到的主要问题是 () 表达式。

更新: GenerateLambda 的 return 类型现在对我来说并不重要。接受任何可以代替 ()=>model.property 的结果。我使用 object 的原因是我不知道属性的通用类型,它们应该是动态的,但正如我测试的那样,可以将 object 转换为 Expression<Func<TValue?>> 这是我需要的最终类型( TValue 是 属性 类型,但将在运行时确定。

我创建了一系列 Blazor 组件,这些组件具有 Expression<Func<TValue?>> 类型的 属性(即 For),用于提取模型的自定义属性。我使用此 属性 的方式是通过以下方式将其设置为 Func:() => person.FirstName。现在我需要为对象(模型)的每个 属性 动态生成这个表达式。假设对象及其类型本身不是动态创建的。

所以对于模型中的每个 属性 p,我想调用 GenerateLambda(object model, string property) 应该 return () => model.p.

伪代码:

foreach(propertyInfo p in model){
   var result= GenerateLambda(model, p, X or any parameter that is needed);
   MyComponent.For= result;
    ... // other logics
}

动态编写高性能的反射和表达式已经解决。一个例子是这个很棒的开源库,它执行此操作并将结果缓存在表达式中以获得最佳性能:https://github.com/ekonbenefits/dynamitey

像这样:

public static IEnumerable<Func<object>> GetGetters(object obj)
{
    var type = obj.GetType();

    var obj2 = Expression.Constant(obj);

    foreach (var prop in type.GetProperties())
    {
        Expression prop2 = Expression.Property(obj2, prop);

        // The boxing for value type is explicit, 
        // downcasting to reference type is implicit
        if (prop2.Type.IsValueType)
        {
            prop2 = Expression.Convert(prop2, typeof(object));
        }

        var lambda = Expression.Lambda<Func<object>>(prop2);
        var compiled = lambda.Compile();
        yield return compiled;
    }
}

这样使用:

var model = new
{
    Prop1 = 1,
    Prop2 = new[] { 1, 2, 3 },
    Prop3 = "Hello"
};

var test = GetGetters(model).ToArray();

这是代码的 v1...更好的版本会在 obj 周围创建闭包并缓存表达式树...不确定是否真的可行。嗯,不……似乎不可能使用表达式树。创建一个方法 returns 另一个方法是表达式树的大忌。你需要反射发射。

明确地说,最佳的是能够生成这个:

public static Func<object>[] MakeGetterProp1(MyClass obj)
{
    Func<object> fn1 = () => obj.Prop1;
    Func<object> fn2 = () => obj.Prop2;
    return new[] { fn1, fn2 };
}

通过使用表达式树。此方法将在第一次构建并缓存。然后你可以调用它并接收一组围绕特定 obj“关闭”的 Fun<object>。我会说不可能。