LINQ“查询语法”是否支持鸭子类型

本文关键字:是否 支持 鸭子 类型 查询语法 查询 语法 LINQ | 更新日期: 2023-09-27 18:26:44

关于 LINQ 查询语法...

var foo = new List<int> { 1, 2 };
var boo = from n in foo
            where n > 1
            select n;

。我一直认为这种语法仅限于在 IEnumerable 上运行。 或者至少在我了解IQueryable之前。 也许IObservable也是如此。 但我最近注意到一个建议,即查询语法基于鸭子类型。这个故事看起来并不十分令人信服,直到我找到了一个专门用于 LINQ to Tasks 的网站。 LINQ to Tasks 看起来完全依赖于带有查询语法的鸭子类型!

好吧,这是怎么回事? 查询语法是否使用鸭子类型? 当我自己尝试一下时,果然这有效,并且似乎证明这完全是关于鸭子打字的,而不是 IEnumerable:

public class Joker<T>
{
    public T Item;
    public Joker(T item)
    {
        Item = item;
    }
}
public static class JokerHelp
{
    public static T2 Select<T,T2>(this Joker<T> joke, Func<T,T2> call)
    {
        return call(joke.Item);
    }
}
var oof = new Joker<int>(5);
int foo = from a in oof
          select a;

如果鸭子类型是查询语法的工作方式,显然是这种情况,那么官方 (MSDN( 文档可能在哪里? 还是任何合理的文件?

LINQ“查询语法”是否支持鸭子类型

C# 中有一些功能,编译器执行结构类型匹配而不是名义类型匹配。例子包括foreach循环、查询理解语法(selectwhere等(和await/async。对于所有这些功能,编译器实际上只是在寻找具有特定名称的方法,而不是特定的接口或类。

这些功能不绑定到特定接口的原因是尽可能将语言与 .NET 框架实现分离。我想这将被认为是鸭子打字的一种形式。

Eric Lippert在这里更彻底地解释了这个功能和推理。

我注意到 MSDN 文档对这些功能的描述通常是错误或不完整的。

你缺少的是List<T>实现IEnumerable<T>。因此,"我一直认为此语法仅限于在IEnumerable上运行"在技术上是正确的,尽管方式有限。 IQueryable 还实现了IEnumerable以及IList和数组。因此,您可以对实现 IEnumerable 的任何内容执行 linq 查询。

由于Joker<>没有实现IEnumerable<>,您的查询尝试将失败。Select<>()Where<>()等扩展方法都是围绕IEnumerable<>构建的。所以,如果你想从oof中进行选择,你只需要更新你的定义Joker<>

public class Joker<T> : IEnumerable<T>
{
  // (actually implement IEnumerable<T> functionality
}

(编辑:在原始格式的问题的上下文中,答案确实有些意义。编辑的问题使我的回答过时(