C# 为 IEnumerable<T> 定义一个扩展方法,它返回 IEnumerable<T>?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/277150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:13:56  来源:igfitidea点击:

Define an Extension Method for IEnumerable<T> which returns IEnumerable<T>?

c#.netextension-methods

提问by SharePoint Newbie

How do I define an Extension Method for IEnumerable<T>which returns IEnumerable<T>? The goal is to make the Extension Method available for all IEnumerableand IEnumerable<T>where Tcan be an anonymous type.

如何定义IEnumerable<T>返回的扩展方法IEnumerable<T>?我们的目标是使扩展方法适用于所有IEnumerableIEnumerable<T>在那里T可以是匿名类型。

采纳答案by Marc Gravell

The easiest way to write any iterator is with an iterator block, for example:

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

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

The key here is the "yield return", which turns the method into an iterator block, with the compiler generating an enumerator (IEnumerator<T>) that does the same. When called, generic type inference handles the Tautomatically, so you just need:

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

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

The above can be used with anonymous types just fine.

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

You can, of coure, specify the Tif you want (as long as it isn't anonymous):

当然,您可以指定T是否需要(只要它不是匿名的):

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

Re IEnumerable(non-generic), well, the simplest approach is for the caller to use .Cast<T>(...)or .OfType<T>(...)to get an IEnumerable<T>first. You can pass in this IEnumerablein the above, but the caller will have to specify Tthemselves, rather than having the compiler infer it. You can't use this with Tbeing an anonymous type, so the moral here is: don't use the non-generic form of IEnumerablewith anonymous types.

Re IEnumerable(非通用),好吧,最简单的方法是让调用者使用.Cast<T>(...).OfType<T>(...)获取IEnumerable<T>第一个。您可以传入this IEnumerable上面的内容,但调用者必须指定T自己,而不是让编译器推断它。您不能将它与T匿名类型一起使用,所以这里的道德是:不要使用IEnumerable匿名类型的非泛型形式。

There are some slightly more complex scenarios where the method signature is such that the compiler can't identify the T(and of course you can't specify it for anonymous types). In those cases, it is usually possible to re-factor into a different signature that the compiler canuse with inference (perhaps via a pass-thru method), but you'd need to post actual code to provide an answer here.

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



(updated)

(更新)

Following discussion, here's a way to leverage Cast<T>with anonymous types. The key is to provide an argument that can be used for the type inference (even if the argument is never used). For example:

经过讨论,这里有一种利用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);
}

回答by Nathan W

This post may help you to get started:How do you write a C# Extension Method for a Generically Typed Class. I'm not sure if it is exactly what you are looking for but it might get you started.

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

回答by Howard Pinsley

using System;
using System.Collections.Generic;

namespace ExtentionTest {
    class Program {
        static void Main(string[] args) {

            List<int> BigList = new List<int>() { 1,2,3,4,5,11,12,13,14,15};
            IEnumerable<int> Smalllist = BigList.MyMethod();
            foreach (int v in Smalllist) {
                Console.WriteLine(v);
            }
        }

    }

    static class EnumExtentions {
        public static IEnumerable<T> MyMethod<T>(this IEnumerable<T> Container) {
            int Count = 1;
            foreach (T Element in Container) {
                if ((Count++ % 2) == 0)
                    yield return Element;
            }
        }
    }
}