我正在阅读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()方法的整个网页都无效。
我错过了什么?
答案 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>
并具有自己的方法(例如Where
,Select
和SelectMany
)的泛型类表,对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<>
的情况下,这可能非常重要,其中有(扩展)方法Where
,Select
等等,它们做了不同的事情(即摄取)将lambda作为表达式树,对其进行分析,并将其“翻译”为SQL或其他内容,而不是Where
上的Select
,IEnumerable<>
等。