5

我正在阅读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

4 回答 4

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

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

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

它将调用默认实现。

真正的好处是当您使用IQueryable实现(例如 LINQ-to-SQL)时,因为例如,Wherefor 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 行为。

于 2013-01-05T12:33:31.650 回答
2

来自MSDN

( AsEnumerable<TSource>)IEnumerable<TSource>方法除了将源的编译时类型从实现的类型更改IEnumerable<T>IEnumerable<T>自身之外没有任何作用。

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

于 2013-01-05T12:01:26.097 回答
1

在您的示例中逻辑上没有意义(即来自数组)。我会假设第一个代码是由初学者编写的,或者 - 更进一步 - 一个示例。

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

那说:

你读了太多的例子。在一个例子中,代码不是为了“好”而是为了展示一个观点。在这种情况下,演示使用 AsEnumerable 可能是有意义的 - 并且 Array 是初始化最快的可枚举对象(就代码行而言),以保持示例简短。示例指出了具体的事情,它们不是任何事情的“好代码”。

于 2013-01-05T11:56:56.773 回答
0

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

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

  // ... use query ...
}

然后我决定改为numbersa 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<>IQueryable<>这在“专门”类型是/继承有(扩展)方法的情况下非常重要WhereSelect等等,这些方法做一些不同的事情(即将 lambda 作为表达式树,分析它,然后“翻译”它成 SQL 什么的)比做Where等等SelectIEnumerable<>

于 2014-01-29T13:42:18.090 回答