C# 为委托类型生成的CIL代码是编译时还是运行时?

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); 这

假设有一个委托引用两个方法,即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);
这是语法糖:

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
的地方查看starting
IL_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