In which cases do I need to create two different extension methods for IEnumerable and IQueryable?

前端 未结 2 2212
隐瞒了意图╮
隐瞒了意图╮ 2021-02-19 14:25

Let\'s say I need an extension method which selects only required properties from different sources. The source could be the database or in-memory collection. So I have defined

相关标签:
2条回答
  • 2021-02-19 15:02

    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.

    0 讨论(0)
  • 2021-02-19 15:20

    If your code only actually works when the objects its dealing with are loaded in memory, just supply the IEnumerable variant and let your callers decide when they want to convert an IQueryable into an in-memory IEnumerable.

    Generally, you won't implement new variations around IQueryable unless you're writing a new database provider.

    0 讨论(0)
提交回复
热议问题