关于 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( 文档可能在哪里? 还是任何合理的文件?
C# 中有一些功能,编译器执行结构类型匹配而不是名义类型匹配。例子包括foreach
循环、查询理解语法(select
、where
等(和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
}
(编辑:在原始格式的问题的上下文中,答案确实有些意义。编辑的问题使我的回答过时(