什么是延迟加载:延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
那么如何实现延迟加载:让我们来思考一下,如何在真正的执行获取数据的时候才加载数据。 从前端的js 延迟加载图片来看,原理是 1、先确定布局 2、设置占位符(大白话:就是说 先设置好html的标签 例如 img标签 div标签) 。 3、绑定事件 (也就是条件判断 什么时候才真正记载) 4、激活事件时 通过js动态加载的方式 为这些标签加载要的内容
例如:<img src="#" data-src=“图片地址”/ 因为src是# 所有没有立即加载图片资源 但是data-src里面保存的图片地址 然后通过绑定事件 来动态替换src 比较 image 的 offsetTop 与 seeHeight + scrollTop 的大小,当小于时则说明图片已经出现过在视口中,这时候继续判断图片是否已经替换过,如果没有替换过,则进行替换。 同理 在C# 中延迟加载 linq 或者 自定义的延迟加载原理也应该大致相同 1、确定代码运行逻辑 2、设置公式(方法 函数 ) 3、设置条件 或者真正调用的方式 4、调用
来我们写一个伪代码
//简单来说就是把方法 当做了参数传递 //在真正调用的时候才执行这个方法参数 并输出结果 void main(){ var witeMetho = funcA(公式x); ... .一堆逻辑判断后 ... witeMetho.invoke(); //这个地方才被真的执行 } void 公式x(){ console.write("我被真正执行了") }接下来我们看看yeid 的运行原理 下面的样例代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace YeidTest { class Program { public static IEnumerable<int> InvokeYeid() { yield return 1; yield return 2; yield return 3; } static void Main(string[] args) { Console.WriteLine("直接输出"); Console.WriteLine(InvokeYeid()); Console.WriteLine("循环输出"); foreach (var item in InvokeYeid()) { Console.Write(item + " "); } Console.WriteLine(""); Console.WriteLine("ToList后输出"); foreach (var item in InvokeYeid().ToList()) { Console.Write(item + " "); } Console.WriteLine(""); Console.WriteLine("直接通过迭代输出"); var enumerator = InvokeYeid().GetEnumerator(); while (enumerator.MoveNext()) { Console.Write(enumerator.Current + " "); } Console.ReadLine(); } } }结果
奇怪的是 直接输出为什么不是 我们想象中的 1 或 2 或3呢 而是一个公式(方法 函数) 其实是因为yeid 实现了延迟加载 只有在迭代的时候 才会真真执行 这也是linq为什么只有 ToList()才会真正执行的原因 如何查看IL (如图) Program方法的IL代码如下
.class private auto ansi beforefieldinit YeidTest.Program extends [mscorlib]System.Object { // 嵌套类型 .class nested private auto ansi sealed beforefieldinit '<InvokeYeid>d__0' extends [mscorlib]System.Object implements class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>, [mscorlib]System.Collections.IEnumerable, class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>, [mscorlib]System.Collections.IEnumerator, [mscorlib]System.IDisposable { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // 成员 .field private int32 '<>2__current' .field private int32 '<>1__state' .field private int32 '<>l__initialThreadId' // 方法 .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> 'System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() // 方法起始 RVA 地址 0x2050 // 方法起始地址(相对于文件绝对值:0x0250) // 代码长度 58 (0x3a) .maxstack 2 .locals init ( [0] class YeidTest.Program/'<InvokeYeid>d__0', [1] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>, [2] bool ) // 0x025C: 28 19 00 00 0A IL_0000: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() // 0x0261: 02 IL_0005: ldarg.0 // 0x0262: 7B 03 00 00 04 IL_0006: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>l__initialThreadId' // 0x0267: 33 0F IL_000b: bne.un.s IL_001c // 0x0269: 02 IL_000d: ldarg.0 // 0x026A: 7B 02 00 00 04 IL_000e: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x026F: 1F FE IL_0013: ldc.i4.s -2 // 0x0271: FE 01 IL_0015: ceq // 0x0273: 16 IL_0017: ldc.i4.0 // 0x0274: FE 01 IL_0018: ceq // 0x0276: 2B 01 IL_001a: br.s IL_001d // 0x0278: 17 IL_001c: ldc.i4.1 // 0x0279: 00 IL_001d: nop // 0x027A: 0C IL_001e: stloc.2 // 0x027B: 08 IL_001f: ldloc.2 // 0x027C: 2D 0B IL_0020: brtrue.s IL_002d // 0x027E: 02 IL_0022: ldarg.0 // 0x027F: 16 IL_0023: ldc.i4.0 // 0x0280: 7D 02 00 00 04 IL_0024: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x0285: 02 IL_0029: ldarg.0 // 0x0286: 0A IL_002a: stloc.0 // 0x0287: 2B 07 IL_002b: br.s IL_0034 // 0x0289: 16 IL_002d: ldc.i4.0 // 0x028A: 73 0B 00 00 06 IL_002e: newobj instance void YeidTest.Program/'<InvokeYeid>d__0'::.ctor(int32) // 0x028F: 0A IL_0033: stloc.0 // 0x0290: 06 IL_0034: ldloc.0 // 0x0291: 0B IL_0035: stloc.1 // 0x0292: 2B 00 IL_0036: br.s IL_0038 // 0x0294: 07 IL_0038: ldloc.1 // 0x0295: 2A IL_0039: ret } // 方法 '<InvokeYeid>d__0'::'System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator' 结束 .method private final hidebysig newslot virtual instance class [mscorlib]System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() // 方法起始 RVA 地址 0x2098 // 方法起始地址(相对于文件绝对值:0x0298) // 代码长度 11 (0xb) .maxstack 1 .locals init ( [0] class [mscorlib]System.Collections.IEnumerator ) // 0x02A4: 02 IL_0000: ldarg.0 // 0x02A5: 28 04 00 00 06 IL_0001: call instance class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> YeidTest.Program/'<InvokeYeid>d__0'::'System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator'() // 0x02AA: 0A IL_0006: stloc.0 // 0x02AB: 2B 00 IL_0007: br.s IL_0009 // 0x02AD: 06 IL_0009: ldloc.0 // 0x02AE: 2A IL_000a: ret } // 方法 '<InvokeYeid>d__0'::System.Collections.IEnumerable.GetEnumerator 结束 .method private final hidebysig newslot virtual instance bool MoveNext () cil managed { .override method instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // 方法起始 RVA 地址 0x20b0 // 方法起始地址(相对于文件绝对值:0x02b0) // 代码长度 131 (0x83) .maxstack 2 .locals init ( [0] bool CS$1$0000, [1] int32 CS$4$0001 ) // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x02BC: 02 IL_0000: ldarg.0 // 0x02BD: 7B 02 00 00 04 IL_0001: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x02C2: 0B IL_0006: stloc.1 // 0x02C3: 07 IL_0007: ldloc.1 // 0x02C4: 45 04 00 00 00 08 00 00 00 02 00 00 00 04 00 00 00 06 00 00 00 IL_0008: switch (IL_0025, IL_001f, IL_0021, IL_0023) // 0x02D9: 2B 08 IL_001d: br.s IL_0027 // 0x02DB: 2B 22 IL_001f: br.s IL_0043 // 0x02DD: 2B 39 IL_0021: br.s IL_005c // 0x02DF: 2B 50 IL_0023: br.s IL_0075 // 0x02E1: 2B 02 IL_0025: br.s IL_0029 // 0x02E3: 2B 54 IL_0027: br.s IL_007d // 0x02E5: 02 IL_0029: ldarg.0 // 0x02E6: 15 IL_002a: ldc.i4.m1 // 0x02E7: 7D 02 00 00 04 IL_002b: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 12,列 9 // 0x02EC: 00 IL_0030: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 13,列 13 // 0x02ED: 02 IL_0031: ldarg.0 // 0x02EE: 17 IL_0032: ldc.i4.1 // 0x02EF: 7D 01 00 00 04 IL_0033: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x02F4: 02 IL_0038: ldarg.0 // 0x02F5: 17 IL_0039: ldc.i4.1 // 0x02F6: 7D 02 00 00 04 IL_003a: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x02FB: 17 IL_003f: ldc.i4.1 // 0x02FC: 0A IL_0040: stloc.0 // 0x02FD: 2B 3E IL_0041: br.s IL_0081 // 0x02FF: 02 IL_0043: ldarg.0 // 0x0300: 15 IL_0044: ldc.i4.m1 // 0x0301: 7D 02 00 00 04 IL_0045: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 14,列 13 // 0x0306: 02 IL_004a: ldarg.0 // 0x0307: 18 IL_004b: ldc.i4.2 // 0x0308: 7D 01 00 00 04 IL_004c: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x030D: 02 IL_0051: ldarg.0 // 0x030E: 18 IL_0052: ldc.i4.2 // 0x030F: 7D 02 00 00 04 IL_0053: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x0314: 17 IL_0058: ldc.i4.1 // 0x0315: 0A IL_0059: stloc.0 // 0x0316: 2B 25 IL_005a: br.s IL_0081 // 0x0318: 02 IL_005c: ldarg.0 // 0x0319: 15 IL_005d: ldc.i4.m1 // 0x031A: 7D 02 00 00 04 IL_005e: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 15,列 13 // 0x031F: 02 IL_0063: ldarg.0 // 0x0320: 19 IL_0064: ldc.i4.3 // 0x0321: 7D 01 00 00 04 IL_0065: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0326: 02 IL_006a: ldarg.0 // 0x0327: 19 IL_006b: ldc.i4.3 // 0x0328: 7D 02 00 00 04 IL_006c: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x032D: 17 IL_0071: ldc.i4.1 // 0x032E: 0A IL_0072: stloc.0 // 0x032F: 2B 0C IL_0073: br.s IL_0081 // 0x0331: 02 IL_0075: ldarg.0 // 0x0332: 15 IL_0076: ldc.i4.m1 // 0x0333: 7D 02 00 00 04 IL_0077: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16,列 9 // 0x0338: 00 IL_007c: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0339: 16 IL_007d: ldc.i4.0 // 0x033A: 0A IL_007e: stloc.0 // 0x033B: 2B 00 IL_007f: br.s IL_0081 // 0x033D: 06 IL_0081: ldloc.0 // 0x033E: 2A IL_0082: ret } // 方法 '<InvokeYeid>d__0'::MoveNext 结束 .method private final hidebysig specialname newslot virtual instance int32 'System.Collections.Generic.IEnumerator<System.Int32>.get_Current' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() // 方法起始 RVA 地址 0x2140 // 方法起始地址(相对于文件绝对值:0x0340) // 代码长度 11 (0xb) .maxstack 1 .locals init ( [0] int32 ) // 0x034C: 02 IL_0000: ldarg.0 // 0x034D: 7B 01 00 00 04 IL_0001: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' // 0x0352: 0A IL_0006: stloc.0 // 0x0353: 2B 00 IL_0007: br.s IL_0009 // 0x0355: 06 IL_0009: ldloc.0 // 0x0356: 2A IL_000a: ret } // 方法 '<InvokeYeid>d__0'::'System.Collections.Generic.IEnumerator<System.Int32>.get_Current' 结束 .method private final hidebysig newslot virtual instance void System.Collections.IEnumerator.Reset () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance void [mscorlib]System.Collections.IEnumerator::Reset() // 方法起始 RVA 地址 0x2157 // 方法起始地址(相对于文件绝对值:0x0357) // 代码长度 6 (0x6) .maxstack 8 // 0x0358: 73 1A 00 00 0A IL_0000: newobj instance void [mscorlib]System.NotSupportedException::.ctor() // 0x035D: 7A IL_0005: throw } // 方法 '<InvokeYeid>d__0'::System.Collections.IEnumerator.Reset 结束 .method private final hidebysig newslot virtual instance void System.IDisposable.Dispose () cil managed { .override method instance void [mscorlib]System.IDisposable::Dispose() // 方法起始 RVA 地址 0x215e // 方法起始地址(相对于文件绝对值:0x035e) // 代码长度 2 (0x2) .maxstack 8 // 0x035F: 00 IL_0000: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0360: 2A IL_0001: ret } // 方法 '<InvokeYeid>d__0'::System.IDisposable.Dispose 结束 .method private final hidebysig specialname newslot virtual instance object System.Collections.IEnumerator.get_Current () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance object [mscorlib]System.Collections.IEnumerator::get_Current() // 方法起始 RVA 地址 0x2164 // 方法起始地址(相对于文件绝对值:0x0364) // 代码长度 16 (0x10) .maxstack 1 .locals init ( [0] object ) // 0x0370: 02 IL_0000: ldarg.0 // 0x0371: 7B 01 00 00 04 IL_0001: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' // 0x0376: 8C 1B 00 00 01 IL_0006: box [mscorlib]System.Int32 // 0x037B: 0A IL_000b: stloc.0 // 0x037C: 2B 00 IL_000c: br.s IL_000e // 0x037E: 06 IL_000e: ldloc.0 // 0x037F: 2A IL_000f: ret } // 方法 '<InvokeYeid>d__0'::System.Collections.IEnumerator.get_Current 结束 .method public hidebysig specialname rtspecialname instance void .ctor ( int32 '<>1__state' ) cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) // 方法起始 RVA 地址 0x2180 // 方法起始地址(相对于文件绝对值:0x0380) // 代码长度 25 (0x19) .maxstack 8 // 0x0381: 02 IL_0000: ldarg.0 // 0x0382: 28 1B 00 00 0A IL_0001: call instance void [mscorlib]System.Object::.ctor() // 0x0387: 02 IL_0006: ldarg.0 // 0x0388: 03 IL_0007: ldarg.1 // 0x0389: 7D 02 00 00 04 IL_0008: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>1__state' // 0x038E: 02 IL_000d: ldarg.0 // 0x038F: 28 19 00 00 0A IL_000e: call int32 [mscorlib]System.Environment::get_CurrentManagedThreadId() // 0x0394: 7D 03 00 00 04 IL_0013: stfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>l__initialThreadId' // 0x0399: 2A IL_0018: ret } // 方法 '<InvokeYeid>d__0'::.ctor 结束 // 属性 .property instance int32 'System.Collections.Generic.IEnumerator<System.Int32>.Current'() { .get instance int32 YeidTest.Program/'<InvokeYeid>d__0'::'System.Collections.Generic.IEnumerator<System.Int32>.get_Current'() } .property instance object System.Collections.IEnumerator.Current() { .get instance object YeidTest.Program/'<InvokeYeid>d__0'::System.Collections.IEnumerator.get_Current() } } // 类 <InvokeYeid>d__0 结束 // 方法 .method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> InvokeYeid () cil managed { // 方法起始 RVA 地址 0x219c // 方法起始地址(相对于文件绝对值:0x039c) // 代码长度 14 (0xe) .maxstack 1 .locals init ( [0] class YeidTest.Program/'<InvokeYeid>d__0', [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> ) // 0x03A8: 1F FE IL_0000: ldc.i4.s -2 // 0x03AA: 73 0B 00 00 06 IL_0002: newobj instance void YeidTest.Program/'<InvokeYeid>d__0'::.ctor(int32) // 0x03AF: 0A IL_0007: stloc.0 // 0x03B0: 06 IL_0008: ldloc.0 // 0x03B1: 0B IL_0009: stloc.1 // 0x03B2: 2B 00 IL_000a: br.s IL_000c // 0x03B4: 07 IL_000c: ldloc.1 // 0x03B5: 2A IL_000d: ret } // 方法 Program::InvokeYeid 结束 .method private hidebysig static void Main ( string[] args ) cil managed { // 方法起始 RVA 地址 0x21b8 // 方法起始地址(相对于文件绝对值:0x03b8) // 代码长度 292 (0x124) .maxstack 2 .entrypoint .locals init ( [0] int32 item, [1] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> enumerator, [2] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> CS$5$0000, [3] bool CS$4$0001, [4] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> CS$5$0002 ) // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 19,列 9 // 0x03C4: 00 IL_0000: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 20,列 13 // 0x03C5: 72 01 00 00 70 IL_0001: ldstr "直接输出" // 0x03CA: 28 1C 00 00 0A IL_0006: call void [mscorlib]System.Console::WriteLine(string) // 0x03CF: 00 IL_000b: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 21,列 13 // 0x03D0: 28 01 00 00 06 IL_000c: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> YeidTest.Program::InvokeYeid() // 0x03D5: 28 1D 00 00 0A IL_0011: call void [mscorlib]System.Console::WriteLine(object) // 0x03DA: 00 IL_0016: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 23,列 13 // 0x03DB: 72 0B 00 00 70 IL_0017: ldstr "循环输出" // 0x03E0: 28 1C 00 00 0A IL_001c: call void [mscorlib]System.Console::WriteLine(string) // 0x03E5: 00 IL_0021: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 24,列 13 // 0x03E6: 00 IL_0022: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 24,列 34 // 0x03E7: 28 01 00 00 06 IL_0023: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> YeidTest.Program::InvokeYeid() // 0x03EC: 6F 11 00 00 0A IL_0028: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() // 0x03F1: 0C IL_002d: stloc.2 .try { // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x03F2: 2B 1F IL_002e: br.s IL_004f // 循环开始 (head: IL_004f) // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 24,列 22 // 0x03F4: 08 IL_0030: ldloc.2 // 0x03F5: 6F 14 00 00 0A IL_0031: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() // 0x03FA: 0A IL_0036: stloc.0 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 25,列 13 // 0x03FB: 00 IL_0037: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 26,列 17 // 0x03FC: 06 IL_0038: ldloc.0 // 0x03FD: 8C 1B 00 00 01 IL_0039: box [mscorlib]System.Int32 // 0x0402: 72 15 00 00 70 IL_003e: ldstr " " // 0x0407: 28 1E 00 00 0A IL_0043: call string [mscorlib]System.String::Concat(object, object) // 0x040C: 28 1F 00 00 0A IL_0048: call void [mscorlib]System.Console::Write(string) // 0x0411: 00 IL_004d: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 27,列 13 // 0x0412: 00 IL_004e: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 24,列 31 // 0x0413: 08 IL_004f: ldloc.2 // 0x0414: 6F 13 00 00 0A IL_0050: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // 0x0419: 0D IL_0055: stloc.3 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x041A: 09 IL_0056: ldloc.3 // 0x041B: 2D D7 IL_0057: brtrue.s IL_0030 // 循环结束 // 0x041D: DE 10 IL_0059: leave.s IL_006b } // .try 结束 finally { // 0x041F: 08 IL_005b: ldloc.2 // 0x0420: 14 IL_005c: ldnull // 0x0421: FE 01 IL_005d: ceq // 0x0423: 0D IL_005f: stloc.3 // 0x0424: 09 IL_0060: ldloc.3 // 0x0425: 2D 07 IL_0061: brtrue.s IL_006a // 0x0427: 08 IL_0063: ldloc.2 // 0x0428: 6F 16 00 00 0A IL_0064: callvirt instance void [mscorlib]System.IDisposable::Dispose() // 0x042D: 00 IL_0069: nop // 0x042E: DC IL_006a: endfinally } // 捕捉结束 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x042F: 00 IL_006b: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 29,列 13 // 0x0430: 72 1B 00 00 70 IL_006c: ldstr "" // 0x0435: 28 1C 00 00 0A IL_0071: call void [mscorlib]System.Console::WriteLine(string) // 0x043A: 00 IL_0076: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 30,列 13 // 0x043B: 72 1D 00 00 70 IL_0077: ldstr "ToList后输出" // 0x0440: 28 1C 00 00 0A IL_007c: call void [mscorlib]System.Console::WriteLine(string) // 0x0445: 00 IL_0081: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 33,列 13 // 0x0446: 00 IL_0082: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 33,列 34 // 0x0447: 28 01 00 00 06 IL_0083: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> YeidTest.Program::InvokeYeid() // 0x044C: 28 01 00 00 2B IL_0088: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>) // 0x0451: 6F 21 00 00 0A IL_008d: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator() // 0x0456: 13 04 IL_0092: stloc.s CS$5$0002 .try { // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0458: 2B 20 IL_0094: br.s IL_00b6 // 循环开始 (head: IL_00b6) // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 33,列 22 // 0x045A: 12 04 IL_0096: ldloca.s CS$5$0002 // 0x045C: 28 22 00 00 0A IL_0098: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current() // 0x0461: 0A IL_009d: stloc.0 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 34,列 13 // 0x0462: 00 IL_009e: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 35,列 17 // 0x0463: 06 IL_009f: ldloc.0 // 0x0464: 8C 1B 00 00 01 IL_00a0: box [mscorlib]System.Int32 // 0x0469: 72 15 00 00 70 IL_00a5: ldstr " " // 0x046E: 28 1E 00 00 0A IL_00aa: call string [mscorlib]System.String::Concat(object, object) // 0x0473: 28 1F 00 00 0A IL_00af: call void [mscorlib]System.Console::Write(string) // 0x0478: 00 IL_00b4: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 36,列 13 // 0x0479: 00 IL_00b5: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 33,列 31 // 0x047A: 12 04 IL_00b6: ldloca.s CS$5$0002 // 0x047C: 28 23 00 00 0A IL_00b8: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext() // 0x0481: 0D IL_00bd: stloc.3 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0482: 09 IL_00be: ldloc.3 // 0x0483: 2D D5 IL_00bf: brtrue.s IL_0096 // 循环结束 // 0x0485: DE 0F IL_00c1: leave.s IL_00d2 } // .try 结束 finally { // 0x0487: 12 04 IL_00c3: ldloca.s CS$5$0002 // 0x0489: FE 16 04 00 00 1B IL_00c5: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> // 0x048F: 6F 16 00 00 0A IL_00cb: callvirt instance void [mscorlib]System.IDisposable::Dispose() // 0x0494: 00 IL_00d0: nop // 0x0495: DC IL_00d1: endfinally } // 捕捉结束 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x0496: 00 IL_00d2: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 37,列 13 // 0x0497: 72 1B 00 00 70 IL_00d3: ldstr "" // 0x049C: 28 1C 00 00 0A IL_00d8: call void [mscorlib]System.Console::WriteLine(string) // 0x04A1: 00 IL_00dd: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 38,列 13 // 0x04A2: 72 31 00 00 70 IL_00de: ldstr "直接通过迭代输出" // 0x04A7: 28 1C 00 00 0A IL_00e3: call void [mscorlib]System.Console::WriteLine(string) // 0x04AC: 00 IL_00e8: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 40,列 13 // 0x04AD: 28 01 00 00 06 IL_00e9: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> YeidTest.Program::InvokeYeid() // 0x04B2: 6F 11 00 00 0A IL_00ee: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() // 0x04B7: 0B IL_00f3: stloc.1 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x04B8: 2B 1D IL_00f4: br.s IL_0113 // 循环开始 (head: IL_0113) // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 42,列 13 // 0x04BA: 00 IL_00f6: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 44,列 17 // 0x04BB: 07 IL_00f7: ldloc.1 // 0x04BC: 6F 14 00 00 0A IL_00f8: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() // 0x04C1: 8C 1B 00 00 01 IL_00fd: box [mscorlib]System.Int32 // 0x04C6: 72 15 00 00 70 IL_0102: ldstr " " // 0x04CB: 28 1E 00 00 0A IL_0107: call string [mscorlib]System.String::Concat(object, object) // 0x04D0: 28 1F 00 00 0A IL_010c: call void [mscorlib]System.Console::Write(string) // 0x04D5: 00 IL_0111: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 45,列 13 // 0x04D6: 00 IL_0112: nop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 41,列 13 // 0x04D7: 07 IL_0113: ldloc.1 // 0x04D8: 6F 13 00 00 0A IL_0114: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // 0x04DD: 0D IL_0119: stloc.3 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 16707566,列 0 // 0x04DE: 09 IL_011a: ldloc.3 // 0x04DF: 2D D9 IL_011b: brtrue.s IL_00f6 // 循环结束 // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 47,列 13 // 0x04E1: 28 24 00 00 0A IL_011d: call string [mscorlib]System.Console::ReadLine() // 0x04E6: 26 IL_0122: pop // 文档: c:\Users\Administrator\Documents\Visual Studio 2012\Projects\YeidTest\YeidTest\Program.cs, 行 48,列 9 // 0x04E7: 2A IL_0123: ret } // 方法 Program::Main 结束 .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // 方法起始 RVA 地址 0x2304 // 方法起始地址(相对于文件绝对值:0x0504) // 代码长度 7 (0x7) .maxstack 8 // 0x0505: 02 IL_0000: ldarg.0 // 0x0506: 28 1B 00 00 0A IL_0001: call instance void [mscorlib]System.Object::.ctor() // 0x050B: 2A IL_0006: ret } // 方法 Program::.ctor 结束 } // 类 YeidTest.Program 结束编译器自动实现了一个 《InvokeYeid》d__0 并在里面重写了 MoveNext() 和 Get_Current()
一、Console.WriteLine(InvokeYeid()) IL_000c: call class [mscorlib]System.Collections.Generic.IEnumerable`1 YeidTest.Program::InvokeYeid() 但是这个地方并没有输出值 而是输出了一个公式(方法 函数) 看看InvokeYeid() 的实现
.method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> InvokeYeid () cil managed { // 方法起始 RVA 地址 0x219c // 方法起始地址(相对于文件绝对值:0x039c) // 代码长度 14 (0xe) .maxstack 1 .locals init ( [0] class YeidTest.Program/'<InvokeYeid>d__0', [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> ) // 0x03A8: 1F FE IL_0000: ldc.i4.s -2 --将提供的 int8 值作为 int32 推送到计算堆栈上(短格式)。 // 0x03AA: 73 0B 00 00 06 IL_0002: newobj instance void YeidTest.Program/'<InvokeYeid>d__0'::.ctor(int32) --创建一个值类型的新对象或新实例,并将对象引用(O 类型)推送到计算堆栈上。 // 0x03AF: 0A IL_0007: stloc.0 --从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。 // 0x03B0: 06 IL_0008: ldloc.0 --将索引 0 处的局部变量加载到计算堆栈上。 // 0x03B1: 0B IL_0009: stloc.1 --从计算堆栈的顶部弹出当前值并将其存储到索引 1 处的局部变量列表中。 // 0x03B2: 2B 00 IL_000a: br.s IL_000c --无条件地将控制转移到目标指令 IL_000c // 0x03B4: 07 IL_000c: ldloc.1 --将索引 1 处的局部变量加载到计算堆栈上。 // 0x03B5: 2A IL_000d: ret --从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。 } // 方法 Program::InvokeYeid 结束 大致意思 就是 实例化了一个<InvokeYeid>d__0 ,并将“对象引用” (对象引用其实就是实例化对象所在的地址) 推送到计算堆栈上 然后把这个 “对象引用” 放入局部变量里面 然后返回这个局部变量 也就是说这个方式实际上 只返回了一个“对象引用” 而不是你想想中的 方法结果1 2 3二、Console.Write(item + " ") 和 Console.Write(enumerator.Current + " ") IL_0023: call class [mscorlib]System.Collections.Generic.IEnumerable`1 YeidTest.Program::InvokeYeid()
IL_0083: call class [mscorlib]System.Collections.Generic.IEnumerable`1 YeidTest.Program::InvokeYeid()
IL_00e9: call class [mscorlib]System.Collections.Generic.IEnumerable`1 YeidTest.Program::InvokeYeid()
也都分别调用了这个方法 唯一不同的是 这3个调用 在之后 都调用了 System.Collections.Generic.IEnumerator`1::get_Current() --获取当前对象 System.Collections.IEnumerator::MoveNext() --移动到下一个对象
这3个方法 都确实输出了 1 2 3
也就是说 实际执行是在get_Current() 和MoveNext() 才真正执行 MoveNext :我就不详细解释IL代码了 IEnumerator将枚举数推进到集合的下一个元素。
get_Current() :
.method private final hidebysig specialname newslot virtual instance int32 'System.Collections.Generic.IEnumerator<System.Int32>.get_Current' () cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) .override method instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() // 方法起始 RVA 地址 0x2140 // 方法起始地址(相对于文件绝对值:0x0340) // 代码长度 11 (0xb) .maxstack 1 .locals init ( [0] int32 ) // 0x034C: 02 IL_0000: ldarg.0 --将索引为 0 的参数加载到计算堆栈上。 // 0x034D: 7B 01 00 00 04 IL_0001: ldfld int32 YeidTest.Program/'<InvokeYeid>d__0'::'<>2__current' --查找对象中其引用当前位于计算堆栈的字段的值。 (很清楚了 获取对象引用的值 真正的执行) // 0x0352: 0A IL_0006: stloc.0 --从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。 // 0x0353: 2B 00 IL_0007: br.s IL_0009 --无条件跳转到 IL_0009 // 0x0355: 06 IL_0009: ldloc.0 --将索引 0 处的局部变量加载到计算堆栈上。 // 0x0356: 2A IL_000a: ret --从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。 } // 方法 '<InvokeYeid>d__0'::'System.Collections.Generic.IEnumerator<System.Int32>.get_Current' 结束 简单来说 就是去的IEnumerator 先获取索引(下标) 然后在<InvokeYeid>d__0 根据索引(下标) 获取对应的值 返回这个值这下非常清晰了 d__0 ,获得“对象引用” 然后通过get_Current() 获取值 并调用MoveNext() 把迭代数的this指针 指向下一个对象
扩展问题 .toLIst();迭代并把值返回给了List 所以调用了get_Current()从而实现了延迟加载 的真正调用
那么问题来了: .First() .FirstOrDefault() .Singe() .SingeOrDefault()
这几个方法呢
聪明的你想到了吧 一样啊 不过是迭代的时候 只获取了第一条记录 (然后根据不同的条件判断 输出了不同的异常而已)
这下我们可以用yeid 来做点好玩的东西了 扩展一个DbContext 来返回一个字典对象
/// <summary> /// 返回动态查询 /// 实际是Ienumerable<IDictionary<string, object>><dy> /// 延迟加载 只有在toList singleOrDealut fristOrDealut 等方法执行才会真真的加载使用 /// </summary> /// <param name="db"></param> /// <param name="Sql"></param> /// <param name="parameters"></param> /// <returns></returns> public static IEnumerable<dynamic> SqlQueryDynamic(this DbContext db, string Sql, params SqlParameter[] parameters) { using (var cmd = db.Database.Connection.CreateCommand()) { cmd.CommandText = Sql; if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } foreach (var p in parameters) { var dbParameter = cmd.CreateParameter(); dbParameter.DbType = p.DbType; dbParameter.ParameterName = p.ParameterName; dbParameter.Value = p.Value; cmd.Parameters.Add(dbParameter); } using (var dataReader = cmd.ExecuteReader()) { while (dataReader.Read()) { //ExpandoObject 表示可在运行时动态添加和删除其成员的对象 var row = new ExpandoObject() as IDictionary<string, object>; for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++) { row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]); } yield return row; } } } }接下来我们可以调用他了
void test(){ houseEntities _wei = new houseEntities(); var sql = 'select name,age from house c' var paramList = new List<SqlParamter>(); var list = _wei.SqlQueryDynamic(sql, paramList.ToArray()).ToList(); //这里返回的是一个动态对象IEnumerable<dynamic> foreach(var item in list ){ console.write(item.name); console.write(item.age); //是不是很奇怪 item.name 这和普通过的写实体接受有啥区别 //大爷的 你看到我写实体了? //是的我们通过这种方式 不写实体 也能使用EF了 和 延迟加载了 } }如果你牛逼 ,你当然还能扩展 实现IEnumerable 的Where()方法 然后你可以 _wei.SqlQueryDynamic(sql, paramList.ToArray()).Where(“c.name = {0}” , “你大爷”)
好吧 今天就说道这了