【问题标题】:Why to Apply AsEnumerable() Method to an Array?为什么要将 AsEnumerable() 方法应用于数组?
【发布时间】:2013-01-05 11:51:48
【问题描述】:

我正在阅读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 直接应用于 array 会产生完全相同的结果:

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() 方法的解释对我来说是无效的。
我错过了什么?

【问题讨论】:

  • +1 这个例子完全是愚蠢的,网页的作者也不知道AsEnumerable是干什么用的。
  • 感谢所有回答者的帮助,尤其感谢评论者@Konrad Rudolph 让我免于与对方法使用语法感兴趣的人混淆。问题的关键是我(但不是引用的文章,我在询问之前理解)错过了什么。我已经阅读了所有答案几次,但我真的更喜欢运行随附的代码插图,而不是阅读非常明智和正确的理论。为了不厌其烦地教育我,似乎正确的答案遭到了反对。

标签: c# arrays linq list ienumerable


【解决方案1】:

这个例子很糟糕,应该感觉很糟糕。这是一个更好的例子:

如果我在数组类型上定义了扩展方法,例如:

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)时,因为例如,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 行为。

【讨论】:

  • 对不起,这是我见过的最荒谬的例子。规则例如:KISS。尽可能简单。提出你提出的一点。你有很多不太好的解释,可能已经或可能还没有,并且交叉引用 - 我只是认真地希望你永远不会写编程教程。
  • @TomTom 你必须完全离开你的摇杆。这个例子是AsEnumerable 所做的完美说明。特别是,这是一个最小示例。它只包含说明其用法的最少成分。我建议你也许在这上面睡一晚,然后再回来看看。
  • @TomTom 我一直喜欢 KISS 的一个变体:“让它尽可能简单,但不要简单。” :) 而且我真的不认为在我解释扩展方法时提出扩展方法过于复杂。
  • LOL 在“这个例子很糟糕,应该感觉很糟糕”
  • 并不是说这个答案不正确或不完整,而是Why use .AsEnumerable() rather than casting to IEnumerable<T>?提供了一些额外的细节(特别是关于 IEnumerable 和 IQueryable)。
【解决方案2】:

来自MSDN

AsEnumerable&lt;TSource&gt;(IEnumerable&lt;TSource&gt;) 方法除了将源的编译时类型从实现IEnumerable&lt;T&gt; 的类型更改为IEnumerable&lt;T&gt; 本身之外没有任何作用。

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

【讨论】:

    【解决方案3】:

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

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

    如是说:

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

    【讨论】:

    • 我不同意。就像你说的那样,“在一个例子中,代码是存在的……来表明一个观点”。问题中的示例完全没有做到这一点,因为将AsEnumerable 应用于数组没有no 点。一个很好的示例将显示在 LINQ to SQL 查询中使用它和不使用它之间的区别。您是否阅读过 OP 链接的网站?它的作者完全一无所知。
    • 这有什么相关性或帮助?不需要告诉任何人如何调用一些常用方法。他们同样可以通过用虚构的名字调用foo.Bar() 来证明这一点,甚至不需要提及System.ArrayAsEnumerable。该示例仅显示此内容。
    【解决方案4】:

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

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

    然后我决定将numbers改为List&lt;int&gt;,然后尝试:

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

    这里的问题是List&lt;&gt; 类有另一个 方法,也称为Reverse。该方法返回void(因为它就地修改了原始List&lt;&gt;)。我不想要那个。一种解决方案是明确地向上转换numbers

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

    但另一个解决方案是AsEnumerable&lt;&gt;,所以:

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

    结论:AsEnumerable 方法的目的是“忘记”特殊类型上碰巧“隐藏”通用类型IEnumerable&lt;&gt; 上的扩展方法的方法。这在“专门”类型是/继承IQueryable&lt;&gt; 的情况下非常重要,其中有(扩展)方法WhereSelect 等等,它们做不同的事情(即摄取 lambda 作为表达式树,分析它,并将其“翻译”成 SQL 或其他东西)而不是在 IEnumerable&lt;&gt; 上执行 WhereSelect 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多