这是真实的,实际的签名是:
public object Execute(Expression expression)
public TResult Execute<TResult>(Expression expression)
然而,并不意味着该TResult将永远是一个单一的元素!这是预期从表达式返回的类型。
此外,请注意,没有限制而不是TResult
,甚至没有'class'或'new()'。
TResult是一个MyObject
当你的表达是单数结果,如.FirstOrDefault()
。但是,当您在查询上使用.Avg()
时,TResult也可以是double
,并且当查询是普通的.Select.Where
时,也可以是IEnumerable<MyObject>
。
证明(*) - 我刚刚设置断点我的执行()里面执行,我已经与手表检查它:
typeof(TResult).FullName "System.Collections.Generic.IEnumerable`1[[xxxxxx,xxxxx]]"
expression.Type.FullName "System.Linq.IQueryable`1[[xxxxxx,xxxxx]]"
我承认三个重载,一个object
,一个TResult
和一个IEnumerable<TResult>
可能会更具可读性。我认为他们没有把它们中的三个作为未来接口的可扩展性。我可以想象,将来他们会想出比IEnumerable
更强大的东西,然后他们需要添加另一个过载等等。用简单的这个接口可以处理任何类型的。
哦,看,我们现在也有IQueryable
除了IEnumerable
,所以它需要至少四个重载:)
证明是标有(*),因为我曾在一个小bug /功能我的IQueryProvider的代码掩盖了LINQ的真实行为。
LINQ确实只为单数情况调用通用执行。这是一个快捷方式,优化。
对于所有其他情况下,...... 不调用execute()它在所有
对于所有其他情况下,LINQ上的自定义IQueryable<>
实现调用.GetEnumerator
,出现这种情况是什么决定通过..只是你写在那里。我的意思是,假设你实际提供了IQueryable的自定义实现。如果你不这么做,那会很奇怪 - 总共只有15行,与自定义提供程序的长度相比没什么差别。
在我从拿到“证明”的项目,我的实现是这样的:
public System.Collections.IEnumerator GetEnumerator()
{
return Provider.Execute<IEnumerable>(this.Expression).GetEnumerator();
}
public IEnumerator<TOut> GetEnumerator()
{
return Provider.Execute<IEnumerable<TOut>>(this.Expression).GetEnumerator();
}
当然
,其中之一是由于名称冲突明确。请注意,为了获取枚举器,我实际上用明确声明的TResult调用Execute。这就是为什么在我的“证据”中出现这些类型的原因。
我认为你看到“TResult =单元素”的情况下,因为你写的即是这样的:
public IEnumerator<TOut> GetEnumerator()
{
return Provider.Execute<TOut>(this.Expression).GetEnumerator();
}
这实际上使你执行不执行选择,并且必须返回单个元素。恕我直言,这只是你的代码中的一个错误。你可以在我的例子都做到了像上面,或者你可以简单地使用非类型化的执行:
public System.Collections.IEnumerator GetEnumerator()
{
return ((IEnumerable)Provider.Execute(this.Expression)).GetEnumerator();
}
public IEnumerator<TOut> GetEnumerator()
{
return ((IEnumerable<TOut>)Provider.Execute(this.Expression)).GetEnumerator();
}
当然,你的执行,执行必须确保返回正确IEnumerables这样的查询!
我认为你错了,请查看我的答案。 – quetzalcoatl 2013-02-18 12:00:23