LINQ“查询语法”是否支持Duck打字?

时间:2013-08-07 21:20:44

标签: c# .net linq duck-typing linq-query-syntax

关于LINQ查询语法......

var foo = new List<int> { 1, 2 };

var boo = from n in foo
            where n > 1
            select n;

......我一直以为这个语法是limited to operating on IEnumerable。或者至少在我了解IQueryable之前。也许IObservable也是如此。但我最近注意到query syntax is based on duck typing的建议。在我发现一个致力于LINQ to Tasks的网站之前,这个故事看起来并不十分令人信服。 LINQ to Tasks看起来完全依赖duck typing查询语法!

好的,这里发生了什么?查询语法是否使用duck typing?当我自己尝试一下时,确实这有效并且似乎证明了所有关于鸭子打字,而不是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)文档?或者任何合理的文件?

2 个答案:

答案 0 :(得分:7)

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

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

Eric Lippert更彻底地解释了这一功能和推理here

我注意到MSDN documentation对于这些功能经常是错误的或不完整的。

答案 1 :(得分:4)

您遗失的是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
}

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