5

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?

  • 3
    +1 the example is completely stupid, and the author of the webpage has no clue what `AsEnumerable` is used for. – Konrad Rudolph Jan 05 '13 at 12:11
  • 1
    Thanks to all the answerers for the help and especially to commenter [@Konrad Rudolph](http://stackoverflow.com/users/1968/konrad-rudolph) for keeping me out of trouble to be confused with a person interested in syntax of a method usage. The key in question was what I (but not the cited article, that I understood before asking) missed. I've read all the answers few times but I really prefer the code illustrations enclosed to be run instead of reading very wise and correct theories. Seems like correct answer has suffered a downvote for the sake of taking trouble to educate me. – Gennady Vanin Геннадий Ванин Jan 05 '13 at 14:56

4 Answers4

4

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.

SWeko
  • 30,434
  • 10
  • 71
  • 106
  • Sorry, that is the most ridiculous example I ahve seen ever. Rule for example: KISS. As simple as possible. TO make the ONE point you make. You have so many not so nice explanations in there that may or may not even be out already and cross reference - I just hope seriously you never ever write a programming tutorial. – TomTom Jan 05 '13 at 14:06
  • 6
    @TomTom You must be completely off your rocker. This example is the *perfect* illustration of what `AsEnumerable` does. In particular, it’s a **minimal** example. It contains nothing but the minimal ingredients to illustrate its usage. I suggest you maybe sleep a night on this, then come back to look at it again. – Konrad Rudolph Jan 05 '13 at 17:29
  • @TomTom I always liked a variation on KISS: "Keep it as simple as possible, but not simpler." :) And I really don't think that bringing up extension methods when I explain an extension method is overcomplicating things. – SWeko Jan 05 '13 at 17:52
  • 1
    LOL at the "this example is bad and it should feel bad" – user541686 Jan 05 '13 at 19:11
  • 1
    Not that this answer is incorrect or incomplete, but slightly additional detail (specifically regarding IEnumerable and IQueryable) is present at [Why use .AsEnumerable() rather than casting to IEnumerable?](http://stackoverflow.com/a/2013876/219516) – publicgk Sep 24 '15 at 07:54
2

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.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
1

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.

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • 1
    I disagree. Like you said, “in an example, code is there … to show a point”. The example in the question utterly fails to do that, since there is *no* point in applying `AsEnumerable` to an array. A good example would show the difference between using it and not using it in a LINQ to SQL query. Have you read the website OP linked to? Its author is completely clueless. – Konrad Rudolph Jan 05 '13 at 12:09
  • 1
    How is that relevant or helpful? Nobody needs to be told how to call some common method. They could equally have demonstrated the same by calling `foo.Bar()` with made-up names, no need to even mention `System.Array` and `AsEnumerable`. The example doesn’t show any more than this. – Konrad Rudolph Jan 05 '13 at 13:01
0

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<>.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181