为委托类型生成的CIL代码是编译时代码还是运行时代码
本文关键字:代码 编译 时代 运行时 CIL 类型 | 更新日期: 2023-09-27 18:14:48
假设有一个委托引用两个方法Add()和Sub()。我所要问的是c#编译器是否在运行时或编译时生成等效的IL代码?
,
public int delegate Dele(int,int);
//methods
int Add(int a,int b)
{
//...
}
int Sub(int a,int b)
{
//...
}
//here comes the condition
if(cond)
{
Del+=Add;
}
else
{
Del+=Sub;
}
int ans=Del(4,4);
这里编译器是否在编译时或运行时为true和false条件生成cil代码?
引用哪个方法仅在调用时才会解析,即在运行时。在我们的例子中,是的,它对优化有一点贡献,因为它只被调用了一次,并且在执行路径中总是只有一个CIL代码。希望这是你正在寻找的答案。
一开始就没有代表的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生成的。
下面这段话摘自第172页的CLI规范:
delegate应该被声明为
sealed
,并且一个delegate只能拥有前面两个方法或者所有四个方法。这些方法应声明为runtime
和managed
(§II.15.4.3)。它们不应该有主体,因为主体将由VES自动创建。委托上可用的其他方法继承自基类库中的System.Delegate
类(参见分区IV)。
表示编译器是否为true和编译时或运行时的错误条件?
生成两个执行路径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
第一个代码执行可以看到从加载Add
的IL_000a
开始。第二个可以在IL_001f
中看到,其中Sub
被加载。
在运行时发生的唯一一件事是创建从MulticastDelegate
继承的委托,其中创建了三个方法:Invoke
, BeingInvoke
和EndInvoke
,如ECMA-335所述:
委托是通过定义派生自基类的类来创建的类型系统。代表(见分区四)。每种代表类型应提供一个名为
Invoke
的方法,并提供适当的参数委托的实例将对其Invoke
方法的调用转发给一个或特定对象上的更多静态或实例方法delegate-assignable-to(§II.14.6.1)代表的签名。的对象和方法是在委托时选择的实例已创建。除了实例构造函数和方法,委托可以有两个额外的方法:BeginInvoke
和EndInvoke
。这些用于异步调用。
// Nested Types
.class nested public auto ansi sealed Dele
extends [mscorlib]System.MulticastDelegate
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method Dele::.ctor
.method public hidebysig newslot virtual
instance int32 Invoke (
int32 x,
int32 y
) runtime managed
{
} // end of method Dele::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult BeginInvoke (
int32 x,
int32 y,
class [mscorlib]System.AsyncCallback callback,
object 'object'
) runtime managed
{
} // end of method Dele::BeginInvoke
.method public hidebysig newslot virtual
instance int32 EndInvoke (
class [mscorlib]System.IAsyncResult result
) runtime managed
{
} // end of method Dele::EndInvoke
} // end of class Dele