动态生成 属性 和空参数的表达式
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>
。我会说不可能。
注意:请注意,这不是重复的。
我需要创建以下 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>
。我会说不可能。