【发布时间】:2013-05-16 04:10:07
【问题描述】:
我对利用 lambda 表达式创建属性选择器树感兴趣。
使用场景是我们有一些代码在对象图上进行一些递归反射,为了限制递归的范围,我们目前使用 Attributes 来标记应该遍历哪些属性。即获取对象的所有修饰属性,如果该属性是具有修饰属性的引用类型,则对每个都重复。
使用属性的限制是您只能将它们放置在您控制其来源的类型上。 lambda 表达式树允许在任意类型的公共成员上定义范围。
用一种简写的方式来定义这些表达式会很方便,它反映了对象图的结构。
最终,我很想拥有这样的东西:
Selector<MyType> selector = new [] {
(t => Property1),
(t => Property2)
{
p => NestedProperty1,
p => NestedProperty2
}
};
现在,我能做的最好的事情就是明确地为每个节点声明一个实例,如下所示:
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)
},
};
这段代码没有任何问题,但是您必须显式地写出每个节点的类型参数,因为编译器无法推断类型参数。这是一种痛苦。而且丑陋。我已经看到了一些令人难以置信的语法糖,并且确信一定有更好的方法。
由于我对“高级”C# 概念(如动力学、协/逆变泛型和表达式树)缺乏了解,我想我会提出这个问题,看看是否有专家知道实现这一目标的方法(或有点像?)
作为参考,这些是实现我在帖子中描述的结构的 Selector 和 SelectorNode 类的声明:
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)
}
};
}
}
为了扩展 nawal 的答案而进行了编辑:
利用 C# 的集合初始化语法,我们可以得到如下代码:
var selector = new Selector<Dummy>
{
(m => m.Child),
{dummy => dummy.Child,
c => c.FakeProperty,
c => c.FakeProperty
}
};
如果我们的 SelectorNode 类的 Add 方法如下所示:
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);
}
}
一定有办法利用这种语法!
【问题讨论】:
-
我认为有办法。你能告诉我们你的 Selector 和 SelectorNode 类吗?我的意思是类型定义和构造函数会做。
-
酷,我编辑了帖子以包含类型定义和一些用法示例。
标签: c# c#-4.0 generics lambda type-inference