如何在属性上正确使用表达式树(无反射)



目标:处理一个对象,如果对象实现了预期类型,我想更改一个特定的属性值(这部分工作正常),我还想将相同的逻辑应用于具有相同预期类型的所有属性列表(我明确指出)。

我有以下代码:

public abstract class BaseObject
{
    public int Id { get; set; }
}
public class Father : BaseObject
{
    public DateTime CreatedOn { get; set; }
    public string Name { get; set; }
    public IEnumerable<ChildA> Children1 { get; set; }
    public IEnumerable<ChildB> Children2 { get; set; }
    public IEnumerable<ChildA> Children3 { get; set; }
    public IEnumerable<ChildB> Children4 { get; set; }
}
public class ChildA : BaseObject
{
    public int Val1 { get; set; }
}
public class ChildB : BaseObject
{
    public string Name { get; set; }
    public int Total { get; set; }
}

我想通过对目标对象上的特定属性和我明确说的所有属性子级应用一些更改来处理对象:

public void Start()
{
    var listA = new List<ChildA> { new ChildA { Id = 1, Val1 = 1 }, new ChildA { Id = 2, Val1 = 2 } };
    var listB = new List<ChildB> { new ChildB { Id = 1, Name = "1", Total = 1 } };
    var obj = new Father { Id = 1, CreatedOn = DateTime.Now, Name = "F1", ChildrenA = listA, ChildrenB = listB };
    // I explicit tell to process only 2 of the 4 lists....
    ProcessObj(obj, x => new object[] { x.Children1, x.Children2 });            
}

我能够编写这个函数:

public void ProcessObj<T>(T obj, Expression<Func<T, object[]>> includes = null)
{
    var objBaseObject = obj as BaseObject;
    if (objBaseObject == null) return;
    // Here I change the ID - add 100 just as an example....
    objBaseObject.Id = objBaseObject.Id + 100;
    if (includes == null) return;
    var array = includes.Body as NewArrayExpression;
    if (array == null) return;
    var exps = ((IEnumerable<object>)array.Expressions).ToArray();
    for (var i = 0; i < exps.Count(); i++)
    {
        var name = ((MemberExpression)exps[i]).Member.Name;
        var childProperty = obj.GetType().GetProperties(
                BindingFlags.Public | BindingFlags.Instance
               ).FirstOrDefault(prop => prop.Name == name);
        if (childProperty == null) continue;
        // NOT correct because I think I am getting a copy of the object 
        // and not pointing to the object in memory (by reference)
        var childList = childProperty.GetValue(obj); 
        // TODO: loop on the list and apply the same logic as the father.... 
        // change the ID field....
    }
}

在这个原型中,我开始写反思,但如果可能的话,我真的很想避免它......

我该怎么做???

也许我错过了一些东西,但似乎你通过使用表达式树使问题复杂化。您不能不使用常规的操作和 Func 委托来执行此操作?为什么它们需要是表达式树?下面是一个仅使用委托的示例:

public void ProcessObj<T>(T obj, Func<T, IEnumerable<object>> includes) {
     var objBaseObject = obj as BaseObject;
    if (objBaseObject == null) return;

    // Create a reusable action to use on both the parent and the children
    Action<BaseObject> action = x => x.Id += 100;
    // Run the action against the root object
    action(objBaseObject);
    // Get the includes by just invoking the delegate. No need for trees.
    var includes = includes(obj);
    // Loop over each item in each collection. If the types then invoke the same action that we used on the root. 
    foreach(IEnumerable<object> include in includes) 
    {
       foreach(object item in include) 
       {
          var childBaseObject = item as BaseObject;
          if(childBaseObject != null) 
          {
            action(childBaseObject);          
          }
       }
    }
}

像以前一样可用:

ProcessObj(obj, x => new object[] { x.Children1, x.Children2 });

没有表达式树,也没有反射,只有常规委托 lambda。

希望有帮助

最新更新