什么是延迟加载:延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
那么如何实现延迟加载:让我们来思考一下,如何在真正的执行获取数据的时候才加载数据。
从前端的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}” , “你大爷”)
好吧 今天就说道这了