代码之家  ›  专栏  ›  技术社区  ›  Michael Puckett II

如何返回<tenumerable,t>:其中tenumerable:ienumerable<t>

  •  6
  • Michael Puckett II  · 技术社区  · 6 年前

    目标:返回时,泛型枚举类型应为相同的类型。

    注意:这在输入类型时有效,但我不理解为什么不能推断它们。

    List<T> 然后返回 列表& T;

    IOrderedEnumerable<T> 然后返回 IOR可撤销<t>

    电子不停车收费系统

    电流法 (仅在输入所有类型时有效)

    public static TEnumerable WithEach<TEnumerable, T>(this TEnumerable items, Action<T> action)
    where TEnumerable : IEnumerable<T>
    {
        foreach (var item in items) action.Invoke(item);
        return items;
    }
    

    仅例

    var list = new List<int>(); //TODO: Mock random values
    list.WithEach(x => Console.WriteLine(x)) //Here WithEach ideally returns List<int> following orignal type List<int>
        .OrderBy(x => x) 
        .WithEach(x => Console.WriteLine(x)); //Here WithEach ideally returns IOrderedEnumerable<int> following OrderBy
    

    使它工作

    var list = new List<int>(); //TODO: Mock random values
    list.WithEach<List<int>, int>(x => Console.WriteLine(x))
        .OrderBy(x => x) 
        .WithEach<IOrderedEnumerable<int>, int>(x => Console.WriteLine(x));
    

    我缺少的是为什么C不能推断类型,尽管 where 过滤器确实使类型准确。我理解为什么你要么提供所有的或者没有通用类型的方法,所以请不要让我指出那些答案。

    编辑:如果我不能推断类型,那我怎么能让它更优雅呢?

    2 回复  |  直到 6 年前
        1
  •  9
  •   Jon Skeet    6 年前

    c中的类型推断是 非常 很复杂——只是一次,我不会让规范出来尝试通过它,因为我知道它会变得多么可怕。

    相信 问题是,两个参数/参数组合都不能为编译器提供足够的信息来推断 T :

    • 这个 TEnumerable items 参数没有提到 T 所以它不用于推断 T ,尽管类型约束
    • 这个 Action<T> 参数可以,但编译器无法根据您提供的lambda表达式进行推理。

    我想不出一个好的方法签名的改变 确切地 您的第一个代码可以工作,但是您可以更改调用方法的方式。 只是一点点 要使其正常工作,请在lambda表达式中指定参数类型:

    var list = new List<int>();
    list.WithEach((int x) => Console.WriteLine(x++))
        .OrderBy(x => x) 
        .WithEach((int x) => Console.WriteLine(x));
    

    当然,这样做的缺点是它不能与匿名类型一起工作。

    一个解决这个缺点的方法是非常可怕的,但是它可以让你表达 T 当需要时,通过一个参数。将方法签名更改为:

    public static TEnumerable WithEach<TEnumerable, T>(
        this TEnumerable items,
        Action<T> action,
        T ignored = default(T))
    

    如果要使用某个匿名类型的列表调用该方法,可以编写:

    list.WithEach(x => Console.WriteLine(x.Name), new { Name = "", Value = 10 });
    

    …最后一个参数将与匿名类型匹配。这将允许 T 由最终参数而不是第二个参数推断。当然,您也可以将其用于其他类型,但我可能会坚持将其用于匿名类型。

    这是一个非常可怕的黑客,我不认为我会 事实上 使用它,但是如果你真的,真的需要它来处理匿名类型,它会处理。

        2
  •  -1
  •   gnud    6 年前

    使用 T ,像这样:

    public static IEnumerable<T> WithEach<T>(this IEnumerable<T> items,Action<T> action)
    {
        foreach (var item in items) action.Invoke(item);
        return items;
    }
    

    这样做的缺点是会丢失您实现的IEnumerable的特定子类。

    对于您关心的特定子类,很容易实现重载:

    public static IOrderedEnumerable<T> WithEach<T>(this IOrderedEnumerable<T> items, Action<T> action)
    {
        ((IEnumerable<T>)items).WithEach(action);
        return items;
    } 
    

    不过,在迭代后返回IEnumerable有点可怕。 IEnumerables可能无法重新启动。