引言

在 MSDN 中对 System.Linq.Enumerable 类的 AsEnumerable 方法相关描述如下所示:

Enumerable.AsEnumerable<TSource> 方法: 返回类型化为 IEnumerable<T> 的输入。
命名空间: System.Linq
程序集: System.Core (在 System.Core.dll 中)
语法: public static IEnumerable AsEnumerable(this IEnumerable source)

备注:
除了将 source 的编译时类型从实现 IEnumerable<T> 的类型更改为 IEnumerable<T> 本身之外,AsEnumerable<TSource>(IEnumerable<TSource>) 方法没做其他任何事。
The AsEnumerable(IEnumerable) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable to IEnumerable itself.

AsEnumerable<TSource>(IEnumerable<TSource>) 可用于在序列实现 IEnumerable<T> 时在查询实现之间进行选择,同时它还具有一组不同的可用公共查询方法。例如,假设给定一个泛型类 Table,该类实现 IEnumerable<T> 并且具有自己的方法(如 Where、Select 和 SelectMany),则调用 Where 将调用 Table 的公共 Where 方法。表示数据库表的 Table 类型可能具有一个 Where 方法,该方法将谓词参数作为表达式目录树,并将该树转换为 SQL 以供远程执行。如果不需要远程执行(例如,谓词调用本地方法),则 AsEnumerable 方法可用于隐藏自定义方法,并使标准查询运算符变为可用。
AsEnumerable<TSource>(IEnumerable<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 method can be used to hide the custom methods and instead make the standard query operators available.

实际上,这个方法只有一条语句,就是原样返回它的唯一参数:

  • reutrn source

使用 .NET Reflector 查看 .NET Framework 4.5 Class Library,就很清楚了:

测试程序

这种只是原样返回它的唯一参数的方法有什么用呢?让我们来看一个例子吧:

 1 using System;
 2 using System.Linq;
 3 using System.Collections.Generic;
 4
 5 namespace Skyiv.Test
 6 {
 7   static class LinqTester
 8   {
 9     class Firster<T> : List<T> { public T First() { return default(T); } }
10     static void Test<T>(Firster<T>     x) { Console.WriteLine("F:" + x.First()); }
11     static void Test<T>(List<T>        x) { Console.WriteLine("L:" + x.First()); }
12     static void Test<T>(IEnumerable<T> x) { Console.WriteLine("I:" + x.First()); }
13
14     static void Main()
15     {
16       var a = new Firster<int> { 2, 3, 5 };
17       Test(a);
18       Test(a as List<int>);
19       Test(a.AsEnumerable());
20     }
21   }
22 }

在上述程序中:

  1. Firster<T> 类是 List<T> 类的派生类。
  2. List<T> 类实现了 IEnumerable<T> 接口。
  3. IEnumerable<T> 接口有一个 First 扩展方法 (定义在 System.Linq.Enumerable 类中)。
  4. Firster<T> 类定义了一个 First 实例方法。

在 Arch Linux 的 Mono 环境下编译和运行:

work$ dmcs LinqTester.cs && mono LinqTester.exe
F:0
L:2
I:2

上述运行结果解释如下:

  1. 第 17 行调用第 10 行的 Test 方法,参数类型是 Firster<T>,于是调用 Firster<T> 类的 First 实例方法,输出: F:0。
  2. 第 18 行调用第 11 行的 Test 方法,参数类型是 List<T>,在 List<T> 类中没有找到 First 方法,由于 List<T> 类实现了 IEnumerable<T> 接口,所以调用 IEnumerable<T> 接口的 First 扩展方法,输出: L:2。
  3. 第 19 行调用第 12 行的 Test 方法,参数类型是 IEnumerable<T>,于是调用 IEnumerable<T> 接口的 First 扩展方法,输出: I:2。

如果在上述程序中,分别进行以下操作:

  • 删除第 10 行的语句
  • 删除第 11 行的语句
  • 删除第 10 行和第 11 行的语句

再重新编译和运行,分别会有什么结果呢?

另外一个测试程序

前面的测试程序引用了 System.Linq 和 System.Collections.Generic 命名空间,涉及到的东东比较复杂。下面我们来一个简单点的测试程序:

 1 using System;
 2
 3 namespace Skyiv.Test
 4 {
 5   class Thing { public string GetId() { return "Thing"; } }
 6
 7   static class Extensions
 8   {
 9     public static object AsObject(this object x) { return x; }
10     public static string GetId(this object x) { return "Object"; }
11   }
12
13   static class Tester
14   {
15     static void Main()
16     {
17       var a = new Thing();
18       var b = a.AsObject();
19       Console.WriteLine(a.GetId());
20       Console.WriteLine(b.GetId());
21     }
22   }
23 }

在上述程序中:

  1. Thing 类定义了一个 GetId 实例方法。
  2. Extensions 类为 object 类定义了一个 GetId 扩展方法。
  3. Extensions 类为 object 类定义了一个 AsObject 扩展方法。

对于上述程序来说,第 18 行的语句使用下面任何一个都是等效的:

  • var b = a.AsObject();
  • var b = (object)a;
  • object b = a;

在 Arch Linux 操作系统的 Mono 环境中编译和运行:

work$ dmcs Tester.cs && mono Tester.exe
Thing
Object

上述运行结果解释如下:

  1. 第 19 行调用了定义在第 5 行的 GetId 实例方法,输出: Thing 。
  2. 第 20 行调用了定义在第 10 行的 GetId 扩展方法,输出: Object 。

使用 monodis 反汇编 Tester.exe,得到 Main 方法的 MSIL 代码如下所示:

 1 .namespace Skyiv.Test
 2 {
 3   .class private auto ansi abstract sealed beforefieldinit Tester extends [mscorlib]System.Object
 4   {
 5     // method line 5
 6     .method private static hidebysig default void Main ()  cil managed
 7     {
 8       // Method begins at RVA 0x2108
 9       .entrypoint
10       // Code size 36 (0x24)
11       .maxstack 7
12       .locals init (
13       class Skyiv.Test.Thing    V_0, object    V_1)
14       IL_0000:  newobj instance void class Skyiv.Test.Thing::'.ctor'()
15       IL_0005:  stloc.0
16       IL_0006:  ldloc.0
17       IL_0007:  call object class Skyiv.Test.Extensions::AsObject(object)
18       IL_000c:  stloc.1
19       IL_000d:  ldloc.0
20       IL_000e:  callvirt instance string class Skyiv.Test.Thing::GetId()
21       IL_0013:  call void class [mscorlib]System.Console::WriteLine(string)
22       IL_0018:  ldloc.1
23       IL_0019:  call string class Skyiv.Test.Extensions::GetId(object)
24       IL_001e:  call void class [mscorlib]System.Console::WriteLine(string)
25       IL_0023:  ret
26     } // end of method Tester::Main
27   } // end of class Skyiv.Test.Tester
28 }

上述 MSIL 代码中:

  1. 第 20 行对应 C# 程序第 19 行的 GetId 实例方法调用 (使用 callvirt 指令)。
  2. 第 23 行对应 C# 程序第 20 行的 GetId 扩展方法调用 (使用 call 指令)。

参考资料

  1. MSDN: (System.Linq) Enumerable.AsEnumerable<TSource> 方法
  2. MSDN: (System.Linq) Enumerable.First<TSource> 方法
  3. MSDN: (System.Linq) Enumerable 类
  4. MSDN: (System.Collections.Generic) List<T> 类

浅谈 System.Linq.Enumerable.AsEnumerable 方法相关推荐

  1. C#集合利用System.Linq.Enumerable.Select()方法执行集合类型转换

    将List<dynamic>集合中的guid转换为强类型的Guid string authorsJson=[{"guid":"e1a2c42d-9337-41 ...

  2. 整理一下 System.Linq.Enumerable 类中的那些比较少用的方法

    Linq 虽然用得多,但是里面有一些方法比较少用,因此整理一下.Enumerable 类的所有方法可以在 MSDN 上查阅到:https://msdn.microsoft.com/zh-cn/libr ...

  3. 必看!清华大学刘洋教授“浅谈研究生学位论文选题”方法,3月7日1小时视频公开课(附视频PPT下载)...

    来源:专知 本文约700字,建议阅读5分钟 清华大学计算机系长聘教授刘洋老师在线讲授了关于<浅谈研究生学位论文选题方法>的课程. 标签:论文研究方法 [ 导读 ]在继续抗击疫情之际,3月7 ...

  4. 【强烈推荐】清华大学刘洋老师【浅谈研究生学位论文选题方法】讲座

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 在继续抗击疫情之际,3月7日,清华大学计算机系长聘教授刘洋老师在线讲授了关于< ...

  5. 经验 | 清华大学计算机系教授~浅谈研究生学位论文选题方法

    点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 编辑:Sophia 计算机视觉联盟  报道  | 公众号 CVLianMeng 转载于 :清华大学,专知 AI博士笔 ...

  6. 浅谈tcpwrapper的基本使用方法

    浅谈tcpwrapper的基本使用方法 曾几何时,不知道你是否与笔者小神一样,有在FreeBSD下实现与WIN2000中的IPSec安全策略实现访问控制的一样功能的想法呢?也许这对刚刚接触FreeBS ...

  7. 计算机维护与维修方法,浅谈计算机维护与维修方法

    题目:浅谈计算机维护与维修方法 作者:周旺红手机:159******** 单位:江苏省徐州机电工程高等职业学校 地址:江苏省徐州市云龙区东店子徐州机电工程高等职业学校云龙校区 邮编:221000 [摘 ...

  8. 浅谈之互联网赚钱的方法

    在互联网上赚钱,努力做得的人都成功了,不过还是有很多人只是把互联网当作一个娱乐的工具看待,却没有想过它能帮你赚钱,即使我们有正经的工作职业,也可以在下班之余利用互联网来赚点生活费.下面可以看看一些互联 ...

  9. 浅谈 System.Data.DataRowCollection 类

    我们来看看以下程序吧: 01: using System; 02: using System.Data; 03: using System.Linq; 04: 05: namespace Skyiv. ...

  10. [2017.11.11特辑]以一个光棍节表白案例浅谈ECMAScript6模块化的使用方法

    双十一,购物节与光棍节,在这个特殊的日子里研究了一下模块化开发的我,突然想结合这个日子,以一个表白的例子浅谈es6模块化的用法. 在之前的 javascript 中一直是没有模块系统的,随着JavaS ...

最新文章

  1. python字典遍历的几种方法(for in 用法)
  2. 淘宝的人工封IP技术真好玩
  3. TIME_WAIT和CLOSE_WAIT状态
  4. Web开发:HTML5、CSS、JavaScript必备教程
  5. 【NOIP2015模拟10.27】魔道研究
  6. ubuntu 关机重启
  7. Qt工作笔记-QGraphics重设场景坐标【标签:Qt图形框架】
  8. springboot项目打war包发布到外置tomcat
  9. 机器学习单词记录--02章单变量相性回归
  10. PostgreSQL(1)数据库安装(win和linux)
  11. 测试通达信指标胜率的软件,如何检测通达信选股公式的成功率?不懂得可以收藏起来自己测一下...
  12. void* LPVOID是些什么东东
  13. 用SQL表达并交差操作
  14. 计算机游戏cpu,2021年11代酷睿cpu游戏电脑配置推荐(可装win7系统)
  15. 超好玩的css3-3d效果
  16. Xray安全评估工具使用
  17. 计算机文化考试论文,计算机文化基础论文
  18. 豌豆荚搜索手机中的游戏app形成列表的原理
  19. 树莓派 11 bullseye镜像官方源和国内源
  20. 喜大普奔!GitHub 官方 App 正式版首发!

热门文章

  1. linux内核之时间子系统
  2. java编程剪刀石头布_Java实现的剪刀石头布游戏示例
  3. Android 网络学习之使用多线程下载,支持断点续传
  4. Uboot下SPI FLASH的添加(SPI 控制器采用软件模拟的方式)
  5. OpenCV---模板匹配
  6. SQlite数据库的C编程接口(五) 便捷函数(Convenience Functions) ——《Using SQlite》读书笔记
  7. linux 内核 内存管理 bootmem alloctor 申请内存
  8. sun服务器如何查cpu信息,solaris 如何查看CPU信息
  9. 3767(按姓名排序)
  10. 企业级数据服务的一点感受