【问题标题】:Why does IEnumerable's Where pass first argument as "this"为什么 IEnumerable Where 将第一个参数作为“this”传递
【发布时间】:2019-12-07 22:25:03
【问题描述】:

我刚刚开始学习 LINQ。以下示例使用Where,它是标准查询运算符之一

string[] names = { "Tom", "Dick", "Harry" };
IEnumerable<string> filteredNames = System.Linq.Enumerable.Where(names, n => n.Length >= 4);

我对它的工作原理做了一些研究,发现this source

public static partial class Enumerable
{
    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
        if (source == null) throw Error.ArgumentNull("source");
        if (predicate == null) throw Error.ArgumentNull("predicate");
        if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
        if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate);
        if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
        return new WhereEnumerableIterator<TSource>(source, predicate);
    }
    /* ... */
}

我不明白为什么它的第一个参数this IEnumerable&lt;TSource&gt; sourcethis 关键字为前缀。我知道扩展方法允许使用新方法扩展现有类型,而无需 改变原始类型的定义和类型 第一个参数将是扩展的类型。

你能解释一下下面的逻辑吗?

【问题讨论】:

  • 你是在问为什么 C#语言要求你写this来定义扩展方法?
  • 非静态方法的实现使得每个方法调用都有一个隐藏参数。所以每一个非静态方法都可以想象成一个静态方法,加上一个额外的参数:this。因此,在扩展方法中将一个参数声明为this 是有意义的。这是一个完美的关键字。
  • 好吧,编译器需要某种方式来将此函数解释为扩展方法。这是由该语法完成的。为什么是this 而不是例如default?怎么会有人知道?
  • @CorentinPane no.

标签: c# arrays .net linq


【解决方案1】:

因为它是Extension Method

所以,而不是

IEnumerable<string> filteredNames = System.Linq.Enumerable.Where(names, n => n.Length >= 4);

你也可以像这样使用它:

IEnumerable<string> filteredNames = names.Where(n => n.Length >= 4);

它是一种扩展方法的原因是 IEnumerable、List……早在 Linq(在 .Net 3.5 中引入)之前就已经存在,它的工作只是扩展查找、过滤、排序……它们。因此,将其作为扩展方法而不是单独的库是合乎逻辑的。并且还考虑到这种方式你可以使用链接,如果它不是一个扩展,这将是可能的:

name.Where(x => x.Length > 4).Select(x => x.Substring(4));

比较一下:

System.Linq.Enumerable.Select(System.Linq.Enumerable.Where(name, x => x.Length > 4), x => x.Substring(4)); 

这只是一个非常简单的问题,考虑一下它对更大、更复杂的查询有多脏。

【讨论】:

  • 如果不是扩展,也就是在IEnumerable的设计时正常参与,还是不能链接吗?例如通过返回this?
  • 没有。因为在我的链接示例中,它必须用作另一个方法的参数Sum(Where(Select(....)))
  • 但如果返回this,则可以调用为...Sum.Where.Select ??我无法理解它的逻辑。你能举个例子吗?
  • 好吧,如果 Where,Select,... 是扩展方法,否则,虽然返回的类型是 IEnumerable(当您返回它时),但它不会有这些方法可用。跨度>
  • 但是如果我有的话,就假设?
【解决方案2】:

因为它是一种扩展方法。这意味着 Where 不是 IEnumerable 上的方法,但是当您引用 Linq 命名空间时,会将 Where 方法添加到 IEnumerable。

有关更多信息,请阅读以下内容: Extension Methods

【讨论】:

    【解决方案3】:

    首先,简单的答案是因为它是一种扩展方法。扩展方法的定义是,它们的第一个参数指定方法操作的类型,参数前面是this修饰符。 其次,我不同意 Ashkan Mobayen Khiabani 最后部分的回答。你必须有一个没有扩展方法的看起来流利的实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-17
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 2017-01-25
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多