为IEnumerable 定义一个扩展方法,它返回IEnumerable ?

如何为IEnumerable定义一个返回IEnumerable的扩展方法? 目标是使扩展方法可用于所有IEnumerableIEnumerable ,其中T可以是匿名类型。

编写任何迭代器的最简单方法是使用迭代器块,例如:

 static IEnumerable Where(this IEnumerable data, Func predicate) { foreach(T value in data) { if(predicate(value)) yield return value; } } 

这里的关键是“ yield return ”,它将方法转换为迭代器块,编译器生成一个枚举器( IEnumerator ),它执行相同的操作。 调用时,generics类型推断自动处理T ,因此您只需要:

 int[] data = {1,2,3,4,5}; var odd = data.Where(i=>i%2 != 0); 

以上可以与匿名类型一起使用就好了。

如果你愿意,你可以指定T (只要它不是匿名的):

 var odd = data.Where(i=>i%2 != 0); 

重新IEnumerable (非generics),最简单的方法是让调用者首先使用.Cast(...).OfType(...)来获取IEnumerable 。 您可以在上面传入this IEnumerable ,但调用者必须自己指定T ,而不是让编译器推断它。 你不能使用T作为匿名类型,所以这里的道德是:不要使用匿名类型的IEnumerable的非genericsforms。

有一些稍微复杂的方案,其中方法签名使得编译器无法识别T (当然,您无法为匿名类型指定它)。 在这些情况下,通常可以重新考虑编译器可以与推理一起使用的不同签名(可能通过pass-thru方法),但是您需要发布实际代码以在此处提供答案。


(更新)

在讨论之后,这里有一种方法可以将Cast与匿名类型结合使用。 关键是提供一个可用于类型推断的参数(即使从不使用参数)。 例如:

 static void Main() { IEnumerable data = new[] { new { Foo = "abc" }, new { Foo = "def" }, new { Foo = "ghi" } }; var typed = data.Cast(() => new { Foo = "never used" }); foreach (var item in typed) { Console.WriteLine(item.Foo); } } // note that the template is not used, and we never need to pass one in... public static IEnumerable Cast(this IEnumerable source, Func template) { return Enumerable.Cast(source); } 
 using System; using System.Collections.Generic; namespace ExtentionTest { class Program { static void Main(string[] args) { List BigList = new List() { 1,2,3,4,5,11,12,13,14,15}; IEnumerable Smalllist = BigList.MyMethod(); foreach (int v in Smalllist) { Console.WriteLine(v); } } } static class EnumExtentions { public static IEnumerable MyMethod(this IEnumerable Container) { int Count = 1; foreach (T Element in Container) { if ((Count++ % 2) == 0) yield return Element; } } } } 

这篇文章可以帮助您入门: 如何为一般类型的类编写C#扩展方法 。 我不确定它是不是你正在寻找的,但它可能会让你开始。