让我们说有一个委托引用两个方法,比如Add()和Sub()。我要问的是C#编译器是在运行时还是在编译时生成等效的IL代码?
前:
SELECT OrderID, OrderDate
FROM Orders
这里编译器是否在编译时或运行时为true和false条件生成cil代码?
答案 0 :(得分:1)
首先没有代表的IL。
Del+=Add;
是
的语法糖Del += new Dele(Add);
Dele
是委托类型。在引擎盖下,这是一个使用Invoke(int, int)
方法(以及BeginInvoke
/ EndInvoke
对)的课程。
致电时:
int ans=Del(4,4);
这是语法糖:
int ans = Del.Invoke(4, 4);
Invoke
方法没有IL代码 - 它被声明为virtual extern
并由运行时处理。当然,调用所需的实际机器代码由JIT生成。
以下是CLI spec,第172页(强调我的)的引用:
代表应宣布为
sealed
,代表所拥有的唯一成员是此处指定的前两种或全部四种方法。这些方法应声明为runtime
和managed
(§II.15.4.3)。 他们没有身体,因为身体应由VES自动创建。 委托上可用的其他方法继承自基类库中的类System.Delegate
(参见分区IV)。
答案 1 :(得分:1)
引用哪种方法仅在调用时解析,即在运行时解析。在我们的例子中,是的,它为优化做出了一些贡献,因为它只被调用一次,并且执行路径中始终只有一个CIL代码。希望这是你正在寻找的答案。
答案 2 :(得分:0)
这里编译器是否生成true和的cil代码 编译时或运行时的错误条件?
生成两个执行路径CIL。您可以通过编译代码示例来看到这一点。这样:
public void X(int x)
{
Dele del;
if(Condition(x))
{
del = new Dele(Add);
del(1,1);
}
else
{
del = new Dele(Sub);
del(2,1);
}
}
public bool Condition(int i)
{
return i % 2 == 0;
}
生成以下IL:
.method public hidebysig
instance void X () cil managed
{
// Method begins at RVA 0x205c
// Code size 51 (0x33)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.5
IL_0002: call instance bool C::Condition(int32)
IL_0007: brfalse.s IL_001e
IL_0009: ldarg.0
IL_000a: ldftn instance int32 C::Add(int32, int32)
IL_0010: newobj instance void C/Dele::.ctor(object, native int)
IL_0015: ldc.i4.1
IL_0016: ldc.i4.1
IL_0017: callvirt instance int32 C/Dele::Invoke(int32, int32)
IL_001c: pop
IL_001d: ret
IL_001e: ldarg.0
IL_001f: ldftn instance int32 C::Sub(int32, int32)
IL_0025: newobj instance void C/Dele::.ctor(object, native int)
IL_002a: ldc.i4.2
IL_002b: ldc.i4.1
IL_002c: callvirt instance int32 C/Dele::Invoke(int32, int32)
IL_0031: pop
IL_0032: ret
} // end of method C::X
第一个代码执行可以从IL_000a
开始加载Add
。第二个可以在加载IL_001f
的{{1}}处看到。
在运行时发生的唯一事情是创建委托,该委托继承自Sub
,其中创建了三个方法:MulticastDelegate
,Invoke
和BeingInvoke
,如ECMA-335中所述:
通过定义从基础派生的类来创建委托 输入System.Delegate(参见Partition IV)。每个代表类型应 提供一个名为
EndInvoke
的方法,其中包含适当的参数 委托的实例将其Invoke
方法的调用转发给一个或 特定对象上的更多静态或实例方法 delegate-assignable-to(§II.14.6.1)代表的签名。该 委托时选择它委派的对象和方法 实例已创建。除了实例构造函数和 调用方法,委托可以选择另外两种方法:Invoke
和BeginInvoke
。这些用于异步调用。
EndInvoke