目标:通用枚举类型与返回时的类型相同。
注意:输入类型时可以使用,但是我不明白为什么不能推断出它们。List<T>
然后返回List<T>
IOrderedEnumerable<T>
然后返回IOrderedEnumerable<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));
我所缺少的是,尽管
where
过滤器确实使类型准确,但C#不能推断类型。我了解您为什么不向方法提供全部或不提供泛型类型,所以请不要将我指向这些答案。编辑:如果我不能推断类型;那我怎样才能使它更优雅呢?
最佳答案
C#中的类型推断非常复杂-只是一次,我不会制定规范来尝试逐步完成它,因为我知道它会变得多么可怕。
我相信问题是参数/参数组合都不给编译器足够的信息来推断T
:
TEnumerable items
参数没有提及T
,因此尽管有类型约束T
。Action<T>
参数会很好,但是编译器无法基于您提供的lamtda表达式进行推断我想不出对方法签名的一个好的更改,它可以使您的第一个代码完全起作用-但您可以通过在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
的类型。当然,您可以将其用于其他类型,但我可能会坚持将其用于匿名类型。这是一个非常可怕的骇客,我不认为我会真正使用它,但是如果您真的需要使用匿名类型,那就可以了。
关于c# - 如何返回<TEnumerable,T> : where TEnumerable:IEnumerable<T>,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53620392/