And*_*ock 11 c# lambda expression-trees
给定一个字符串:"Person.Address.Postcode"我希望能够在Person的实例上获取/设置此postcode属性.我怎样才能做到这一点?我的想法是将字符串拆分为"." 然后遍历各个部分,查找前一个类型的属性,然后构建一个看起来像(伪语法道歉)的表达式树:
(person => person.Address) address => address.Postcode
Run Code Online (Sandbox Code Playgroud)
虽然我真的很麻烦地创建表达式树!如果这是最好的方式,有人可以建议如何去做,还是有更简单的选择?
谢谢
安德鲁
public class Person
{
public int Age { get; set; }
public string Name { get; set; }
public Address Address{ get; set; }
public Person()
{
Address = new Address();
}
}
public class Address
{
public string Postcode { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 21
听起来你是用常规反射排序的,但是对于info,构建嵌套属性的表达式的代码与这个order-by代码非常相似.
请注意,要设置值,您需要GetSetMethod()在属性上使用并调用它 - 在构造之后没有用于分配值的内置表达式(尽管4.0中支持).
(编辑)像这样:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
public Foo() { Bar = new Bar(); }
public Bar Bar { get; private set; }
}
class Bar
{
public string Name {get;set;}
}
static class Program
{
static void Main()
{
Foo foo = new Foo();
var setValue = BuildSet<Foo, string>("Bar.Name");
var getValue = BuildGet<Foo, string>("Bar.Name");
setValue(foo, "abc");
Console.WriteLine(getValue(foo));
}
static Action<T, TValue> BuildSet<T, TValue>(string property)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
ParameterExpression valArg = Expression.Parameter(typeof(TValue), "val");
Expression expr = arg;
foreach (string prop in props.Take(props.Length - 1))
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
// final property set...
PropertyInfo finalProp = type.GetProperty(props.Last());
MethodInfo setter = finalProp.GetSetMethod();
expr = Expression.Call(expr, setter, valArg);
return Expression.Lambda<Action<T, TValue>>(expr, arg, valArg).Compile();
}
static Func<T,TValue> BuildGet<T, TValue>(string property)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
return Expression.Lambda<Func<T, TValue>>(expr, arg).Compile();
}
}
Run Code Online (Sandbox Code Playgroud)
为什么不使用递归?就像是:
setProperyValue(obj, propertyName, value)
{
head, tail = propertyName.SplitByDotToHeadAndTail(); // Person.Address.Postcode => {head=Person, tail=Address.Postcode}
if(tail.Length == 0)
setPropertyValueUsingReflection(obj, head, value);
else
setPropertyValue(getPropertyValueUsingReflection(obj, head), tail, value); // recursion
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11078 次 |
| 最近记录: |