0

关于 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)文档可能在哪里?或者任何合理的文件?

4

2 回答 2

7

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

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

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

我注意到MSDN 文档中关于这些功能的内容通常是错误的或不完整的。

于 2013-08-07T22:02:10.363 回答
4

您缺少的是List<T>实现IEnumerable<T>. 因此,“我一直认为这种语法仅限于在 IEnumerable 上运行”在技术上是正确的,尽管方式有限。IQueryable实现IEnumerable以及以及IList和数组。因此,您可以对任何实现IEnumerable.

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

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

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

于 2013-08-07T21:26:42.773 回答