【问题标题】:Dynamically generate expression of property and empty argument动态生成属性表达式和空参数
【发布时间】:2020-12-24 05:52:12
【问题描述】:

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

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

() => model.property

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

public object GenerateLambda(object model, string property) 
{

}

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

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

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

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

伪代码:

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

【问题讨论】:

  • 请为问题提供更多背景信息并阐明要求。如果你想要lambda表达式,那么object不是所需函数public object GenerateLambda(object model, string property)的正确返回类型,应该是public LambdaExpression GenerateLambda(...)?还提供一个示例如何调用它以及它将用于什么。
  • @IvanStoev 谢谢我会添加更多细节
  • 很好,但现在我们必须等待获得足够的重新开票。
  • @IvanStoev 现在开张了!

标签: c# lambda reflection expression


【解决方案1】:

类似这样的:

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 周围创建闭包并缓存表达式树...不确定是否真的可行。嗯,不...用表达式树进行柯里化似乎是不可能的。创建一个返回另一个方法的方法是表达式树的一大禁忌。你需要反射发射。

需要明确的是,最好是能够生成这个:

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

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

【讨论】:

  • 谢谢你,它没有任何问题。虽然我删除了编译部分,但表达式本身完成了这项工作。
【解决方案2】:

已经解决了高性能动态编写反射和表达式的问题。一个例子是这个伟大的开源库,它可以做到这一点并将结果缓存在表达式中以获得最佳性能:https://github.com/ekonbenefits/dynamitey

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多