which methods can be used to "close" a compiled query.
Methods that return a sequence use deferred execution, unless the method is something like ToXYZ
. Where
, Select
, Take
, Skip
, GroupBy
and OrderBy
etc falls under this. Methods that return a single object forces execution of query, like First
, Single
, ToList
and ToArray
, ToDictionary
, ToLookup
, Any
, All
etc. See this excellent thread for more: Linq - What is the quickest way to find out deferred execution or not?
I know most people use either .AsEnumerable() or .ToList(), but which other methods work as well? Can I use .AsQueryable(), or is this a no-op?
They all are different. Justin has a grand explanation. You might also want to see: What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()? which has a good answer.
In general, you can understand the semantics of a method by seeing the name of the method itself. A method named AsSomething
implies it does nothing but returns the input as something. That may or may not involve returning a new object, but a reference is somehow maintained. For instance, aList<T>.AsEnumerable()
merely does a cast to IEnumerable<T>
(of course it has bigger meaning in linq context). You can cast it back to List<T>
and mutate it reflecting the change everywhere. To test it:
var list = new List<int> { 1, 2 };
var enum = list.AsEnumerable();
var newlist = enum as List<string>;
newlist.Add(3);
//print enum.Count() -> 3
While methods that look like ToSomething
, you get a totally new object often transformed to something else.
var list = new List<int> { 1, 2 };
var newlist = list.ToList();
newlist.Add(3);
//print list.Count -> 2
Let's consider something outside the context of linq. object.ToString()
results in new string representation (strings are anyway immutable so thats a bit pointless). An interesting semantics is that of List<T>.AsReadonly
which returns a new ReadOnlyCollection<T>
instance, but mutating the list outside of it changes the internal list of ReadOnlyCollection<T>
too, hence the naming AsReadonly
.
var list = new List<int> { 1, 2 };
var readonlylist = list.AsReadonly();
list.Add(3);
//print readonlylist.Count -> 3