简体   繁体   中英

C# - AsEnumerable Example

What is the exact use of AsEnumerable? Will it change non-enumerable collection to enumerable collection?.Please give me a simple example.

From the "Remarks" section of the MSDN documentation :

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

If you take a look in reflector:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
    return source;
}

It basically does nothing more than down casting something that implements IEnumerable.

Nobody has mentioned this for some reason, but observe that something.AsEnumerable() is equivalent to (IEnumerable<TSomething>) something . The difference is that the cast requires the type of the elements to be specified explicitly, which is, of course, inconvenient. For me, that's the main reason to use AsEnumerable() instead of the cast.

AsEnumerable() converts an array (or list, or collection) into an IEnumerable<T> of the collection.

See http://msdn.microsoft.com/en-us/library/bb335435.aspx for more information.

From the above article:

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.
static void Main()
    {
        /* 
        "AsEnumerable" purpose is to cast an IQueryable<T> sequence to IEnumerable<T>, 
        forcing the remainder of the query to execute locally instead of on database as below example so it can hurt performance.  (bind  Enumerable operators instead of Queryable). 

        In below example we have cars table in SQL Server and are going to filter red cars and filter equipment with some regex:
        */
        Regex wordCounter = new Regex(@"\w");
        var query = dataContext.Cars.Where(car=> article.Color == "red" && wordCounter.Matches(car.Equipment).Count < 10);

        /* 
        SQL Server doesn’t support regular expressions  therefore the LINQ-to-db  providers  will  throw  an  exception: query  cannot  be translated to SQL.

        TO solve this firstly we can get all cars with red color using a LINQ to SQL query, 
        and secondly filtering locally for Equipment of less than 10 words:
        */

        Regex wordCounter = new Regex(@"\w");

        IEnumerable<Car> sqlQuery = dataContext.Cars
          .Where(car => car.Color == "red");
        IEnumerable<Car> localQuery = sqlQuery
          .Where(car => wordCounter.Matches(car.Equipment).Count < 10);

        /*
        Because sqlQuery is of type IEnumerable<Car>, the second query binds  to the local query operators,
        therefore that part of the filtering is run on the client.

        With AsEnumerable, we can do the same in a single query:

         */
        Regex wordCounter = new Regex(@"\w"); 
        var query = dataContext.Cars
          .Where(car => car.Color == "red")
          .AsEnumerable()
          .Where(car => wordCounter.Matches(car.Equipment).Count < 10);

        /*
        An alternative to calling AsEnumerable is ToArray or ToList.
        */
    }

AsEnumerable can only be used on enumerable collections. It just changes the type of the collection to IEnumerable<T> to access more easily the IEnumerable extensions.

No it doesn't change a non-enumerable collection to an enumerable one. What is does it return the collection back to you as an IEnumerable so that you can use it as an enumerable. That way you can use the object in conjunction with IEnumerable extensions and be treated as such.

After reading the answers, i guess you are still missing a practical example.

I use this to enable me to use linq on a datatable

var mySelect = from table in myDataSet.Tables[0].AsEnumerable()
            where table["myColumn"].ToString() == "Some text"
            select table;

Here's example code which may illustrate LukeH's correct explanation.

IEnumerable<Order> orderQuery = dataContext.Orders
  .Where(o => o.Customer.Name == "Bob")
  .AsEnumerable()
  .Where(o => MyFancyFilterMethod(o, MyFancyObject));

The first Where is Queryable.Where , which is translated into sql and run in the database (o.Customer is not loaded into memory).

The second Where is Enumerable.Where , which calls an in-memory method with an instance of something I don't want to send into the database.

Without the AsEnumerable method, I'd have to write it like this:

IEnumerable<Order> orderQuery =
  ((IEnumerable<Order>)
    (dataContext.Orders.Where(o => o.Customer.Name == "Bob")))
  .Where(o => MyFancyFilterMethod(o, MyFancyObject));

Or

IEnumerable<Order> orderQuery =
  Enumerable.Where(
    dataContext.Orders.Where(o => o.Customer.Name == "Bob"),
    (o => MyFancyFilterMethod(o, MyFancyObject));

Neither of which flow well at all.

The Enumerable.AsEnumerable method can be used to hide a type's custom implementation of a standard query operator

Consider the following example. we have a custom List called MyList

public class MyList<T> : List<T>
{
    public string Where()
    {
        return $"This is the first element {this[0]}";
    }
}

MyList has a method called Where which is Enumerable.Where() exact same name. when I use it, actually I am calling my version of Where , not Enumerable 's version

MyList<int> list = new MyList<int>();

list.Add(4);
list.Add(2);
list.Add(7);

string result = list.Where();

// the result is "This is the first element 4"

Now how can I find the elements which are less than 5 with the Enumerable 's version of Where ?

The answer is: Use AsEnumerable() method and then call Where

IEnumerable<int> result = list.AsEnumerable().Where(e => e < 5);

This time the result contains the list of elements that are less than 5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM