注意:请重新标记和/或重新命名
我有一个类FooEnumerator
,它包装Foo
并实现IEnumerable<FooEnumerator>
。 Foo
表示树状数据结构,枚举的FooEnumerator
是当前节点的子节点。
Foo
是供应商提供的数据对象。 FooEnumerator
实现了一堆自定义过滤代码。
class FooEnumerator : IEnumerable<FooEnumerator>
{
public Foo WrappedNode { get; private set; }
public string Name { get { return WrappedNode.Name; } }
public int Id { get{ return WrappedNode.Id; } }
public DateTime Created { get{ return WrappedNode.Created; } }
public FooEnumerator(Foo wrappedNode)
{
WrappedNode = wrappedNode;
}
public IEnumerator<FooEnumerator> GetEnumerator()
{
foreach (Foo child in this.GetChildren())
if(FilteringLogicInHere(child))
yield return new FooEnumerator(child);
}
...
}
我希望能够使用在创建顶级FooEnumerator
时定义的给定(任意)表达式对树的每个级别进行排序,并将此表达式传递给每个要使用的新枚举项。
我想使用lambda来定义sort表达式,就像使用OrderBy函数一样。事实上,我打算将lambda传递给OrderBy
。
OrderBy的签名是
OrderBy<TSource, TKey>(Func<TSource, TKey> keySelector)
其中TKey
是给定Func
的返回类型,但在方法签名中是一个类型参数,在编译时计算出来。
使用示例
var x = GetStartingNode();
var sort = n => n.DateTime;
var enu = new FooEnumerator(x, sort);
var sort2 = n => n.Name;
var enu2 = new FooEnumerator(x, sort2);
然后,排序表达式将存储在类变量中,FooEnumerator
的工作方式如下:
// pseudo-implementation
private Expression<Func<Foo, TKey>> _sortBy;
public FooEnumerator(Foo wrappedNode, Expression<Func<Foo, TKey>> sortBy)
{
WrappedNode = wrappedNode;
_sortBy = sortBy;
}
public IEnumerator<FooEnumerator> GetEnumerator()
{
foreach (Foo child in this.GetChildren().OrderBy(_sortBy))
if(FilteringLogicInHere(child))
yield return new FooEnumerator(child);
}
如何在此用例中指定TKey的类型(隐式或显式)?
我不想硬编码,因为我希望能够对基础Foo
的任何和所有属性进行排序。
答案 0 :(得分:4)
好吧,您无法创建Expression<Func<Foo,TKey>>
类型的成员委托变量,因为从未指定TKey
。但是,您可以创建Expression<Func<Foo,IComparable>>
类型的成员,这可能足以满足您的目的。当然,您可能需要更改FooEnumerator
构造函数以接受此签名。
编辑:其他人建议您对FooEnumerator
进行参数设置,使其接受TKey
。你当然可以做到这一点,但你应该意识到出现的问题:
FooEnumerator<T>
的代码都必须具有{{1}类型的先验知识。 }。但是,您可以实现非通用接口T
来处理它。IFooEnumerator
,FooEnumerator<T>
,FooEnumerator<T1,T2>
等等很尴尬。答案 1 :(得分:1)
您还可以参数化您的枚举器:
class FooEnumerator<TKey> {
// ... All your 'pseudo' code would work here
}
我建议使用IComparable
对接口进行编程。