在哪种情况下,我需要为IEnumerable和IQueryable创建两种不同的扩展方法? [英] In which cases do I need to create two different extension methods for IEnumerable and IQueryable?
问题描述
比方说,我需要一个扩展方法,该方法仅从不同来源中选择所需的属性.源可以是数据库或内存中的集合.所以我定义了这样的扩展方法:
public IQueryable<TResult> SelectDynamic<TResult>(
this IQueryable<T> source,
...)
这对于IQueryable
s正常工作.但是,我还必须为IEnumerable
s调用此函数.
在这种情况下,我可以借助.AsQueryable()
来调用它:
myEnumerable.AsQueryable()
.SelectDynamic(...)
.ToList();
两者都很好.而且,如果两种方法都能正常工作,在哪种条件下,我必须创建两种不同的扩展方法以达到相同的目的,一种用于IEnumerable
,另一种用于IQueryable
?
如果是Queryable
,我的方法必须将查询发送到数据库.
例如,这是System.Linq
命名空间中.Select
扩展方法的来源:
我再次重复我的主要问题:
在使用Queryable
的情况下,我的方法必须将查询发送到数据库,但使用IEnumerable
时则不是.现在,我将AsQueryable()
用于枚举.因为,我不想为Enumerable
编写相同的代码. 它会产生一些副作用吗?
myEnumerable.AsQueryable()
返回自定义对象:new EnumerableQuery<TElement>(myEnumerable);
(.Select
for IEnumerable
.Select
for IQueryableI am repeating my main question again:
My method must send query to the database in case of Queryable
, but not when working with IEnumerable
. And for now, I am using AsQueryable()
for the enumerables. Because, I dont want to write same code for the Enumerable
. Can it have some side effects?
myEnumerable.AsQueryable()
returns a custom object: new EnumerableQuery<TElement>(myEnumerable);
(source code)
This EnumerableQuery
class implements IEnumerable<T>
and IQueryable<T>
When using the EnumerableQuery
result of .AsQueryable()
as an IEnumerable
, the implementation of the interface method IEnumerable<T>.GetIterator()
simply returns the original source iterator, so no change and minimal overhead.
When using the result of .AsQueryable()
as an IQueriable
, the implementation of the interface property IQueriable.Expression
simply returns Expression.Constant(this)
, ready to be evaluated later as an IEnumerable when the whole expression tree is consumed.
(All the other methods and code paths of EnumerableQuery
are not really relevant, when the EnumerableQuery is constructed directly from an IEnumerable, as far as I can tell)
If I understand you correctly, you have implemented your method selectDynamic<TResult>()
in such a way that you construct an expression tree inside the method, that produces the desired result when compiled.
As far as I understand the source code, when you call e.g. myEnumerable.AsEnumerable().selectDynamic().ToList()
, the expression tree you constructed is compiled and executed on myEnumerable, and the total overhead should be fairly minimal, since all this work is only done once per query, not once per element.
So i think there is nothing wrong with implementing your IEnumerable Extension method like this:
public IEnumerable<TResult> SelectDynamic<TResult>(
this IEnumerable<T> source,...)
return source.AsQueryable().SelectDynamic();
}
There is some slight overhead, since this compiles the query once each time this method is called, and I am not sure the JITer is smart enough to cache this compilation. But I think that will not be noticeable in most circumstances, unless you execute this query a thousand times per second.
There should be no other side efects, apart from slight performance issues, in implementing the IEnumerable extension method in this way.
这篇关于在哪种情况下,我需要为IEnumerable和IQueryable创建两种不同的扩展方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!