c# - 为返回 IEnumerable<T> 的 IEnumerable<T> 定义扩展方法?

标签 c# .net extension-methods

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

最佳答案

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

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

这里的关键是“yield return”,它把方法变成一个迭代器 block ,编译器生成一个枚举器(IEnumerator<T>)做同样的事情。调用时,泛型类型推断处理 T自动,所以你只需要:

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

以上可以很好地与匿名类型一起使用。

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

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

回复 IEnumerable (非通用),嗯,最简单的方法是让调用者使用 .Cast<T>(...).OfType<T>(...)得到一个IEnumerable<T>第一的。可以传入this IEnumerable在上面,但调用者必须指定 T他们自己,而不是让编译器推断它。你不能将它与 T 一起使用作为匿名类型,所以这里的原则是:不要使用 IEnumerable 的非泛型形式匿名类型。

有一些稍微复杂的场景,其中方法签名使得编译器无法识别 T (当然你不能为匿名类型指定它)。在这些情况下,通常可以重构为编译器可以用于推理的不同签名(可能通过直通方法),但您需要将实际代码发布到在这里提供答案。


(更新)

经过讨论,这是一种利用 Cast<T> 的方法与匿名类型。关键是提供一个可用于类型推断的参数(即使从未使用过该参数)。例如:

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<T> Cast<T>(this IEnumerable source, Func<T> template)
{
    return Enumerable.Cast<T>(source);
}

关于c# - 为返回 IEnumerable<T> 的 IEnumerable<T> 定义扩展方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/277150/

相关文章:

c# - 在 Windows 资源管理器中创建特殊文件夹,例如 DropBox 或 OneDrive

c# - 现在和下一个小时之间的时间跨度?

c# - 我应该使用扩展方法来帮助从 DataRow/Table 创建模型对象吗?

.net - 私有(private)成员命名约定

c# - 扩展方法不会在 Razor 中显示

c# - 隐藏部分面板C#

c# - 将 txt 文件保存到错误的位置

c# - CSS 在设计 View 中显示而不是在运行时

.NET List<T> Concat 与 AddRange

c# - 使用非实例化对象的扩展方法,即 String.F()