且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何返回< TEnumerable,T> :其中TEnumerable:IEnumerable< T>

更新时间:2022-03-13 15:03:23

C#中的类型推断非常复杂[em] -仅此一次,我不打算尝试使用该规范通过它,因为我知道它会变得多么可怕.

Type inference in C# is very complicated - just for once, I'm not going to get the spec out to try to step through it, because I'm aware of just how horrible it can become.

相信问题是参数/参数组合都不给编译器足够的信息来推断T:

I believe the problem is that neither of the parameter/argument combinations gives the compiler enough information to infer T:

  • TEnumerable items参数未提及T,因此尽管存在类型约束,它也不能用于推断T
  • Action<T>参数很好,但是编译器无法基于您提供的lambda表达式进行推断
  • The TEnumerable items parameter doesn't mention T, so it isn't used to infer T, despite the type constraint
  • The Action<T> parameter would be fine, but the compiler can't make an inference based on the lambda expression you're providing

我想不出对方法签名的一个很好的改变,以使完全成为您的第一个代码,但是您可以稍微改变一下方法的调用方式通过在lambda表达式中指定参数类型来使其工作:

I can't think of a good change to the method signature that would make exactly your first code work - but you can change how you invoke the method just a little to make it work, by specifying the parameter type in the lambda expression:

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

其缺点是,它当然不适用于匿名类型.

The downside of that is that it won't work with anonymous types, of course.

该缺点的一种解决方法非常可怕,但是它使您可以在需要时通过参数来表示T的类型.您将方法签名更改为:

One workaround for that downside is a pretty horrible one, but it lets you express the type of T via a parameter instead, when you need to. You change the method signature to:

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

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

If you wanted to call the method with a list of some anonymous type, you could write:

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

...,其中最后一个参数将与匿名类型匹配.这将允许通过最后一个参数而不是第二个参数来推断T的类型.当然,您可以将其用于其他类型,但我可能会坚持将其用于匿名类型.

... where the final argument would match the anonymous type. That will allow the type of T to be inferred by the final parameter instead of the second one. You can use that for other types of course, but I'd probably stick to using it for anonymous types instead.

这都是一个非常可怕的hack,我不认为我会实际使用它,但是如果您真的需要使用匿名类型,那就可以了.

That's all a pretty horrible hack, and I don't think I'd actually use it, but if you really, really need this to work with anonymous types, it would cope.