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

时间:2015-09-28 16:24:38

标签: c# .net optimization delegates cil

让我们说有一个委托引用两个方法,比如Add()和Sub()。我要问的是C#编译器是在运行时还是在编译时生成等效的IL代码?

前:

SELECT OrderID, OrderDate
FROM Orders

这里编译器是否在编译时或运行时为true和false条件生成cil代码?

3 个答案:

答案 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,代表所拥有的唯一成员是此处指定的前两种或全部四种方法。这些方法应声明为runtimemanaged   (§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,其中创建了三个方法:MulticastDelegateInvokeBeingInvoke,如ECMA-335中所述:

  

通过定义从基础派生的类来创建委托   输入System.Delegate(参见Partition IV)。每个代表类型应   提供一个名为EndInvoke的方法,其中包含适当的参数   委托的实例将其Invoke方法的调用转发给一个或   特定对象上的更多静态或实例方法   delegate-assignable-to(§II.14.6.1)代表的签名。该   委托时选择它委派的对象和方法   实例已创建。除了实例构造函数和   调用方法,委托可以选择另外两种方法:   InvokeBeginInvoke。这些用于异步调用。

EndInvoke