c# - 传递 TResult 未知的 Func<T, TResult>

标签 c# generics lambda

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


我有课,FooEnumerator ,它包装了一个 Foo并实现 IEnumerable<FooEnumerator> . Foo s 代表树状数据结构,FooEnumerator枚举出来的s是当前节点的子节点。

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>> 的成员委托(delegate)变量自 TKey从未指定。但是,您可以创建类型为 Expression<Func<Foo,IComparable>> 的成员这可能足以满足您的目的。您可能需要更改您的 FooEnumerator当然,构造函数也接受这个签名。

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

  1. 通过对枚举器进行参数化,您就可以完成任务了。任何想要存储 FooEnumerator<T> 的代码必须具有类型的先验知识 T .但是,您可以实现非通用接口(interface) IFooEnumerator来处理这个问题。
  2. 如果您想在将来支持对多个字段的排序,那么参数化枚举器会产生问题。C# 不支持具有可变数量类型参数的泛型,这限制了需要的泛型的创建多种任意类型。这个问题比较难处理,因为开始创建 FooEnumerator<T> 很尴尬, FooEnumerator<T1,T2> , FooEnumerator<T1,T2,T3...> , 等等。

关于c# - 传递 TResult 未知的 Func<T, TResult>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4189131/

相关文章:

c# - 窗体 GUI 视频线程通信

Java - 使用带有接口(interface)的哈希表作为值

c++模板方法语法问题

c# - 如何从泛型列表中提取派生类型?

c# - 如何为lambda表达式中的匿名变量编写IEqualityComparer?

python - 对 Pandas 中 Python Lambda 函数的澄清/思考

haskell - 是否可以通过修改这个简单的 reducer 来展示不同的评估策略?

c# - 使用 SWIG 将指针从 C++ 返回到 C#

c# - 如何将数据添加到合并字段

c# - 查找 MongoDB 文档并仅匹配带有 C# 驱动程序的数组元素