为IEnumerable 定义一个扩展方法,它返回IEnumerable ?
如何为IEnumerable
定义一个返回IEnumerable
的扩展方法? 目标是使扩展方法可用于所有IEnumerable
和IEnumerable
,其中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#扩展方法 。 我不确定它是不是你正在寻找的,但它可能会让你开始。