注意:请重新标记和/或重新命名



我有一个类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定义排序表达式,就像使用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的所有属性进行排序。

最佳答案

好的,您不能创建类型为Expression<Func<Foo,TKey>>的成员委托变量,因为从未指定TKey。但是,您可以创建一个Expression<Func<Foo,IComparable>>类型的成员,该成员可以满足您的目的。当然,您可能需要更改FooEnumerator构造函数以接受此签名。

编辑:其他人建议参数化您的FooEnumerator,以便它接受TKey。您当然可以这样做,但是您应该意识到出现的问题:


通过对枚举器进行参数设置,您便可以轻松完成工作。任何要存储FooEnumerator<T>的代码都必须具有T类型的先验知识。但是,您可以实现一个非通用接口IFooEnumerator来处理该问题。
如果希望将来支持对多个字段进行排序,则对枚举器进行参数设置会产生问题。 C#不支持带有可变数量的类型参数的泛型,这限制了需要多个任意类型的泛型的创建。这个问题很难处理,因为开始创建FooEnumerator<T>FooEnumerator<T1,T2>FooEnumerator<T1,T2,T3...>等很麻烦。

10-08 04:37