使用lambda表达式的嵌套集合创建一个对象图 [英] Using nested collections of lambda expressions to create an object graph

查看:876
本文介绍了使用lambda表达式的嵌套集合创建一个对象图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我感兴趣的是利用lambda表达式创建属性选择的树。

I am interested in utilizing lambda expressions to create a tree of property selectors.

的使用情况是,我们有一些代码,做一个对象的某些回归反射图,并且,我们目前正在使用的属性标记的属性应遍历的递归限制的范围。即获取对象的所有装饰性,如果该属性是引用类型具有装饰性,重复每个那些了。

The usage scenario is that we have some code that does some recursive reflection on an object graph, and to limit the scope of recursion, we're currently using Attributes to mark which properties should be traversed. i.e. Get all decorated properties of object, if that property is a reference type with decorated properties, repeat for each of those too.

使用属性的限制是,你可以只有把他们放在你的类型的控制源。 lambda表达式树允许在任意类型的公众成员所定义的范围。

The limitation of using Attributes is that you can only place them on Types you control the source for. A tree of lambda expressions allows the scope to be defined on any arbitrary type's public members.

这将是方便有速记的方式来定义这些表达式,它反映了对象图的结构。

It would be handy to have a shorthand way to define these expressions, which reflects the structure of the object graph.

最后,我很想有这样的事情:

Ultimately, I'd love to have something like this:

Selector<MyType> selector = new [] {
        (t => Property1),
        (t => Property2)
        {
                p => NestedProperty1,
                p => NestedProperty2
        }
};



现在,我所能做的最好声明为每个节点明确这样的一个实例:

Right now, the best I can do declares an instance for each node explicitly something like this:

var selector = new Selector<MyType>()
{
    new SelectorNode<MyType, Property1Type>(t => Property1),
    new SelectorNode<MyType, Property2Type>(t => Property2)
    {
        new SelectorNode<Property2Type, NestedProperty1Type>(p => NestedProperty1),
        new SelectorNode<Property2Type, NestedProperty2Type>(p => NestedProperty2)
    },
};

有没有错码的,但你必须明确地写出每个节点的类型参数,因为编译器不能推断类型参数。这是一种痛苦。和丑陋。我已经看到了一些令人难以置信的语法糖在那里,我相信一定有更好的办法。

There's nothing wrong with this code, but you have to write out the type arguments for each node explicitly, since the compiler can't infer the type arguments. This is a pain. And ugly. I've seen some incredible syntactical sugar out there, and am sure there must be a better way.

由于我缺乏像动态更高C#概念的理解,CO /逆变泛型和表达式树,我想我会场上的问题在那里,看是否有大师知道的一种方式来实现这一(或东西,而喜欢吗?)

Owing to my lack of understanding of 'higher' C# concepts like dynamics, co/contravariant generics and expression trees, I thought I'd pitch the question out there and see if any gurus know of a way to achieve this (or something rather like it?)

有关参考,这些都为选择 SelectorNode 类:

For reference, these are the declarations for the Selector and SelectorNode classes that achieve the structure I described in my post:

public interface ISelectorNode<T> {}

public class Selector<T>: List<ISelectorNode<T>>{}

public class SelectorNode<T, TOut>: List<ISelectorNode<TOut>>, ISelectorNode<T> 
{
    public SelectorNode(Expression<Func<T, TOut>> select) {}
}

//Examples of Usage below

public class Dummy
{
    public ChildDummy Child { get; set; }
}

public class ChildDummy
{
    public string FakeProperty { get; set; }
}

public class Usage
{
    public Usage()
    {
        var selector = new Selector<Dummy>
        {
            new SelectorNode<Dummy, ChildDummy>(m => m.Child)
            {
                new SelectorNode<ChildDummy, string>(m => m.FakeProperty)
            }
        };
    }
}






编辑在扩大对纳瓦尔的回答的利益:


Edited in the interest of expanding on nawal's answer:

利用C#的集合初始化语法,我们可以得到的代码如下:

Leveraging C#'s collection initializer syntax, we can get code to look like:

var selector = new Selector<Dummy>
  {
      (m => m.Child),
      {dummy => dummy.Child, 
          c => c.FakeProperty,
          c => c.FakeProperty                    
      }
  };

这是,如果我们的SelectorNode类的添加方法如下:

This is if our SelectorNode class' Add method looks like:

public class Selector<T> : List<ISelectorNode<T>>
{
    public SelectorNode<T, T, TOut> Add<TOut>(Expression<Func<T, TOut>> selector, params Expression<Func<TOut, object>>[] children)
    {
        return SelectorNode<T, T, TOut>.Add(this, this, selector);
    }
}

有必须要利用这个语法的方式!

There must be a way to leverage this syntax!

推荐答案

我在这个阶段,我已经变得麻木思维太多选择承认,希望这是我最后一次..:)

I have to admit at this stage I have gotten numb thinking too many options, hoping this is my last.. :)

最后,你在你的问题中提到一个 - 表达式来; Func键< T,对象>> 路线。我不知道我怎么能更好这一点没有失去一些编译时的安全性。非常相似,我的第一个答案:

Lastly, the one you have mentioned in your question - Expression<Func<T, object>> route. I have no idea how can I better this without losing some compile time safety. Very similar to my first answer:

public class Selector<T> : List<ISelectorNode<T>>
{
    public static SelectorNode<T, TOut> Get<TOut>(Expression<Func<T, TOut>> selector)
    {
        return new SelectorNode<T, TOut>(selector);
    }

    public void Add<TOut>(Expression<Func<T, TOut>> selector)
    {
        var node = new SelectorNode<T, TOut>(selector);
        Add(node);
    }
}



public class SelectorNode<T, TOut> : List<ISelectorNode<TOut>>, ISelectorNode<T>
{

    public SelectorNode(Expression<Func<T, TOut>> selector)
    {

    }

    public ISelectorNode<T> Add(params Expression<Func<TOut, object>>[] selectors)
    {
        foreach (var selector in selectors)
            base.Add(new SelectorNode<TOut, object>(selector));

        return this;
    }

    public ISelectorNode<T> Add(params ISelectorNode<TOut>[] nodes)
    {
        AddRange(nodes);
        return this;
    }
}

和调用:

var selector = new Selector<Person>
{
    Selector<Person>.Get(m => m.Address).Add
    (
        Selector<Address>.Get(x => x.Place),
        Selector<Address>.Get(x => x.ParentName).Add
        (
            x => x.Id,
            x => x.FirstName,
            x => x.Surname
        )
    ),

    Selector<Person>.Get(m => m.Name).Add
    (
        x => x.Id,
        x => x.FirstName,
        x => x.Surname
    ),

    m => m.Age
};

这一切的是我最喜欢到现在为止(如果提供)。

Of all this is my fav until now (if that serves)..

这篇关于使用lambda表达式的嵌套集合创建一个对象图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆