0

Is there a recommended built-in type in C# that collections can be converted/cast to that will still allow deferred execution, but not allow the type to be cast back into IQueryable? (Like IEnumerable<T> can in some cases)

adam0101
  • 29,096
  • 21
  • 96
  • 174

2 Answers2

4

The "built in" way to guard IQueryable<T> would be Enumerable.Select like this

IQueryable<T> source = ...;
var result = source.AsEnumerable().Select(x => x); 

AsEnumerable is not enough because it is a simply cast. But it's needed to ensure Enumerable.Select is used instead of Queryable.Select.

However, other than being "built in", I see no benefit of this approach and prefer the custom extension method like in another answer, although this can be used as implementation instead of iterator function (which also has no benefit, but rather a drawback due to unnecessary delegate call, so really the custom iterator function is the right way to go).

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
3

A built in type no but it's pretty easy to do :

public static class Utils
{
    public static IEnumerable<T> AsDefferedEnumerable<T>(this IQueryable<T> Source)
    {
        foreach (var item in Source)
        {
            yield return item;
        }
    }
}

This way you're not returning a casted IQueryable (that could be casted back) but creating a new IEnumerable wrapping it , you don't even need a new type at all for that you just end up with an IEnumerable that will itself enumerate the IQueryable as it is enumerated without exposing it.

Edit : sample of a wrapper object (untested)

public class HideImplementationEnumerable<T>
{
public HideImplementationEnumerable(IEnumerable<T> Source)
{
    this.Source = Source;
}

private IEnumerable<T> Source;

public IEnumerable<T> Value
{
    get
    {
        foreach (var item in Source)
        {
            yield return item;
        }
    }
}
}
Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78
  • I like this approach, but my reason for wanting a different type was so a code reviewer could see at a glance that the return type is something that code downstream cannot alter the query with. – adam0101 Jan 19 '16 at 14:52
  • @adam0101 That sounds unecessary, if a code reviewer sees an IEnumerable all he should assume is that he can enumerate it, but changing this to a type is trivial, editing my answer now for a type version (a type also has other advantages, it is pretty useless to do "just that" but it can be extended to do caching etc.)* – Ronan Thibaudau Jan 19 '16 at 14:56