C# 为委托类型生成的CIL代码是编译时还是运行时?
假设有一个委托引用两个方法,即Add()和Sub()。我要问的是,C#编译器是在运行时还是在编译时生成等效的IL代码 例:C# 为委托类型生成的CIL代码是编译时还是运行时?,c#,.net,optimization,delegates,cil,C#,.net,Optimization,Delegates,Cil,假设有一个委托引用两个方法,即Add()和Sub()。我要问的是,C#编译器是在运行时还是在编译时生成等效的IL代码 例: 在这里,编译器是在编译时还是在运行时为true和false条件生成cil代码?首先没有用于委托的IL Del+=Add; 语法上的糖是什么 Del += new Dele(Add); Dele是代理类型。在后台,这是一个具有Invoke(int,int)方法(以及BeginInvoke/EndInvoke对)的类 当你打电话时: int ans=Del(4,4); 这
在这里,编译器是在编译时还是在运行时为true和false条件生成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代码-它被声明为virtualextern
,并由运行时处理。当然,调用所需的实际机器代码由JIT确定
这里引用了第172页(我的重点): 代表应声明为密封的,代表应拥有的唯一成员是此处规定的前两种或全部四种方法。这些方法应声明为
运行时
和管理
(§II.15.4.3)它们不应有主体,因为主体应由VES自动创建。
委托上可用的其他方法继承自基类库中的类System.Delegate
(参见分区IV)
这里,编译器是否为true和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
第一次代码执行可以在加载Add
的地方查看startingIL_000a
。第二个可以在加载了Sub
的IL_001f
处看到
运行时唯一发生的事情是创建从多播委托
继承的委托,其中创建了三种方法:调用
、正在调用
和结束调用
,如中所述:
委托是通过定义从基派生的类来创建的
键入System.Delegate(参见第四部分)。每种代表类型应
提供一个名为Invoke
的方法,并提供相应的参数
委托的实例将对其Invoke
方法的调用转发给一个或多个
特定对象上的更多静态或实例方法
可转让给(§II.14.6.1)代表签名的代表。这个
当委托被选中时,将选择它所委托的对象和方法
实例被创建。除了实例构造函数和
调用方法时,委托可以有两个附加方法:
BeginInvoke
和EndInvoke
。它们用于异步调用
引用的方法只有在调用时才能解析,即在运行时。在我们的例子中,是的,它对优化有一点贡献,因为它只被调用过一次,并且在执行路径中总是只有一个CIL代码。希望这就是您要寻找的答案。为什么不看看编译时生成的MSIL,看看?
ildasm
工具在这方面很好。在这种情况下,代理可以帮助优化吗???@Necromacer代理相当快,是的,但我不知道它们与优化有什么关系。如果你有一个优化问题,你应该把它作为一个新问题发布在这里,并说明你的具体情况。
.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
// 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