博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈 System.Linq.Enumerable.AsEnumerable 方法
阅读量:6228 次
发布时间:2019-06-21

本文共 5432 字,大约阅读时间需要 18 分钟。

引言

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

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,就很清楚了:

AsEnumerable

测试程序

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

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
: List
{ public T First() { return default(T); } }10 static void Test
(Firster
x) { Console.WriteLine("F:" + x.First()); }11 static void Test
(List
x) { Console.WriteLine("L:" + x.First()); }12 static void Test
(IEnumerable
x) { Console.WriteLine("I:" + x.First()); }13 14 static void Main()15 {16 var a = new Firster
{ 2, 3, 5 };17 Test(a);18 Test(a as List
);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.exeF:0L:2I: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 Tester14   {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.exeThingObject

上述运行结果解释如下:

  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       .entrypoint10       // Code size 36 (0x24)11       .maxstack 712       .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::Main27   } // end of class Skyiv.Test.Tester28 }

上述 MSIL 代码中:

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

参考资料

转载地址:http://kznna.baihongyu.com/

你可能感兴趣的文章
校园-秋
查看>>
document.getElementsByName 在IE与firefox表现不一,解决办法
查看>>
IXWebHosting的URL转向设置
查看>>
octopress的一些总结
查看>>
Linux- systemd
查看>>
TCP编程的迷惑
查看>>
【转】这个“哭喊着要进步”的电子工程师一路怎么走过来的~
查看>>
使用Lambda实现递归
查看>>
opengl overlay plane
查看>>
静态库和动态库
查看>>
近来有不少博友向本人提向,鉴于本站的邮件系统不是很好用,建议大家加入本人的QQ群...
查看>>
[转] SQL Server 批量 停用/启用 外键约束
查看>>
Bug管理工具
查看>>
Django performance
查看>>
touch — 设定文件的访问和修改时间
查看>>
Spark集群模式&Spark程序提交
查看>>
package-info.java(转载)
查看>>
Hash
查看>>
QuickFlow之动态子流程
查看>>
通常每个套接字地址 (协议/网络地址/端口) 只允许使用一次
查看>>