为什么要将AsEnumerable()方法应用于数组?

时间:2013-01-05 11:51:49

标签: c# arrays linq list ienumerable

我正在阅读C# AsEnumerable

  

“IEnumerable接口是一个通用接口。这意味着它   定义类型可以实现循环的模板。该   AsEnumerable方法是一种通用方法,允许您转换特定的方法   键入其IEnumerable等效“

此外,代码示例:

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);
        }
    }
}

听起来我需要将数组转换为 IEnumerable 类型对象以使用循环( foreach ?)。

但将 foreach 直接应用于数组会产生完全相同的结果:

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);
        }
    }
}

因此,对我来说,解释 AsEnumerable()方法的整个网页都无效。
我错过了什么?

4 个答案:

答案 0 :(得分:4)

这个例子很糟糕,应该感觉很糟糕。这是一个更好的,如果有点人为的例子:

如果我有一个扩展方法,比方说,数组类型,如下所示:

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;
    }

}

我做了

int[] nums = new []{1,2,3,4,5};
nums.Any(n=> n % 2 == 0);

如果将执行并运行我的实现,即使我不需要它。通过做

nums.AsEnumerable().Any(n => n % 2 == 0);

它将调用默认实现。

真正的好处是当您使用IQueryable实现(例如LINQ-to-SQL)时,因为,例如,Where for IEnumerable被定义为

public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate) 

IQueryable.Where定义为

public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)

当IQueryable行为不受欢迎时,可以调用AsEnumerable()来强制IEnumerable行为。

答案 1 :(得分:2)

来自MSDN

AsEnumerable<TSource>IEnumerable<TSource>)方法除了将源代码的编译时类型从实现IEnumerable<T>的类型更改为IEnumerable<T>之外无效。< / p>

AsEnumerable<TSource>IEnumerable<TSource>)可用于在序列实现IEnumerable<T>时选择查询实现,但也可以使用一组不同的公共查询方法。例如,给定一个实现IEnumerable<T>并具有自己的方法(例如WhereSelectSelectMany)的泛型类表,对Where的调用将会调用Table的公共Where方法。表示数据库表的表类型可以具有Where方法,该方法将谓词参数作为表达式树并将树转换为SQL以进行远程执行。如果不需要远程执行,例如因为谓词调用本地方法,AsEnumerable<TSource>方法可用于隐藏自定义方法,而是使标准查询运算符可用。

答案 2 :(得分:1)

在您的逻辑示例中(即从数组中)没有任何意义。我假设第一个代码是由初学者编写的,或者 - 更多的是 - 一个例子。

在LINQ意义上它确实有意义,因为“AsEnumerable”触发查询的评估并且取决于ORM这可能意味着释放数据库连接以便在循环内重用。

这意味着:

你读了太多的例子。在一个例子中,代码不是“好”而是要表明一点。在这种情况下,对于使用AsEnumerable进行DEMONSTRATE可能是有意义的 - 而Array是最快的可枚举对象(根据代码行),以保持示例简短。例子指出了具体的事情,它们不是任何东西的“好代码”。

答案 3 :(得分:0)

这只是另一个例子。假设我有这个方法:

static void MyMeth(int[] numbers)
{
  var query = numbers.Reverse();  // works fine, calls Linq extension

  // ... use query ...
}

然后我决定将numbers更改为List<int>,然后尝试:

static void MyMeth(List<int> numbers)
{
  var query = numbers.Reverse();  // will not compile!

  // ... use query ...
}

这里的问题是List<>类有另一个方法,也称为Reverse。该方法返回void(因为它会就地修改原始List<>)。我不希望这样。一种解决方案是明确地numbers

static void MyMeth(List<int> numbers)
{
  var query = ((IEnumerable<int>)numbers).Reverse();  // fine; Linq

  // ... use query ...
}

但另一个解决方案是AsEnumerable<>,所以:

static void MyMeth(List<int> numbers)
{
  var query = numbers.AsEnumerable().Reverse();  // fine too; Linq

  // ... use query ...
}

结论: AsEnumerable方法的目的是“忘记”在常规类型IEnumerable<>上“隐藏”扩展方法的专用类型上的方法。在“特殊”类型为/ {inherited IQueryable<>的情况下,这可能非常重要,其中有(扩展)方法WhereSelect等等,它们做了不同的事情(即摄取)将lambda作为表达式树,对其进行分析,并将其“翻译”为SQL或其他内容,而不是Where上的SelectIEnumerable<>等。