Reputation: 10384
I am reading C# AsEnumerable:
"The IEnumerable interface is a generic interface. This means it defines a template that types can implement for looping. The AsEnumerable method, a generic method, allows you to cast a specific type to its IEnumerable equivalent"
Further on, a code example:
using System;
using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
var query = array.AsEnumerable();
foreach (var element in query)
{
Console.WriteLine(element);
}
}
}
Sounds like I need to convert an array to an IEnumerable type object to use looping (foreach?).
But applying foreach directly to an array yields exactly the same results:
using System;
//using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
//var query = array.AsEnumerable();
foreach (var element in array)
{
Console.WriteLine(element);
}
}
}
So, the entire webpage with an explanation of AsEnumerable() method is void for me.
What did I miss?
Upvotes: 5
Views: 3344
Reputation: 61952
This is just another example. Suppose I have this method:
static void MyMeth(int[] numbers)
{
var query = numbers.Reverse(); // works fine, calls Linq extension
// ... use query ...
}
Then I decide to change numbers
into a List<int>
instead, and try:
static void MyMeth(List<int> numbers)
{
var query = numbers.Reverse(); // will not compile!
// ... use query ...
}
The problem here is that the List<>
class has another method which is also called Reverse
. That method returns void
(because it modifies the original List<>
in-place). I don't want that. One solution would be to upcast numbers
explicitly:
static void MyMeth(List<int> numbers)
{
var query = ((IEnumerable<int>)numbers).Reverse(); // fine; Linq
// ... use query ...
}
But another solution would be AsEnumerable<>
, so:
static void MyMeth(List<int> numbers)
{
var query = numbers.AsEnumerable().Reverse(); // fine too; Linq
// ... use query ...
}
Conclusion: The purpose of AsEnumerable
method is to "forget" methods on the specialized type that happen to "hide" the extension methods on the general type IEnumerable<>
. This can be incredibly important in the case where the "specialized" type is/inherits IQueryable<>
where there are (extension) methods Where
, Select
and so on which do something different (namely ingest the lambda as an expression tree, analyze it, and "translate" it into SQL or something) than do Where
, Select
etc. on IEnumerable<>
.
Upvotes: 0
Reputation: 30902
The example is bad and it should feel bad. Here is a better, if somewhat contrived example:
If I have an extension method defined on the, let's say, the array type, like this:
public static class ArrayExtension {
public static bool Any<T>(this T[] source, Func<T,bool> predicate)
{
Console.WriteLine("Undesirable side behaviour");
SomeResourceIntensiveOperation();
Console.WriteLine("Inefficient implementation");
return source.Where(predicate).Count() != 0;
}
}
and I do
int[] nums = new []{1,2,3,4,5};
nums.Any(n=> n % 2 == 0);
If will execute and run my implementation, even if i do not need that. By doing
nums.AsEnumerable().Any(n => n % 2 == 0);
it will call the default implementation.
The real benefit is when you are using IQueryable
implementations (e.g. LINQ-to-SQL), because, for example, the Where
for IEnumerable is defined as
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
but the IQueryable.Where
is defined with
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)
When the IQueryable behaviour is undesireable one can call the AsEnumerable()
to force the IEnumerable behaviour.
Upvotes: 4
Reputation: 33381
From MSDN
The AsEnumerable<TSource>
(IEnumerable<TSource>
) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable<T>
to IEnumerable<T>
itself.
AsEnumerable<TSource>
(IEnumerable<TSource>
) can be used to choose between query implementations when a sequence implements IEnumerable<T>
but also has a different set of public query methods available. For example, given a generic class Table that implements IEnumerable<T>
and has its own methods such as Where
, Select
, and SelectMany
, a call to Where
would invoke the public Where
method of Table. A Table type that represents a database table could have a Where method that takes the predicate argument as an expression tree and converts the tree to SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable<TSource>
method can be used to hide the custom methods and instead make the standard query operators available.
Upvotes: 2
Reputation: 62101
It makes no sense in YOUR example logically (i.e. from array). I would assume the first code has been written by a beginner, or - more down - an example.
It does make sense in the sense of LINQ as "AsEnumerable" triggers the evaluation of the query and depending on the ORM That can mean freeing up a database connection for a reuse within the loop.
THAT SAID:
You read too much into examples. In an example, code is there not to be "good" but to show a point. In this case it may make sense to DEMONSTRATE the use of AsEnumerable - and an Array is the fastest enumerable object to initialize (in terms of lines of code), to keep the example short. Examples point out specific things, they are not "good code" for anything.
Upvotes: 1