委托类型生成的CIL代码是编译时的还是运行时的?
Whether the CIL code generated for a delegate type is compile time or runtime?
假设有一个委托引用了两个方法,即 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);
这里编译器是在编译时还是运行时为真假条件生成cil代码?
首先,委托没有 IL。
Del+=Add;
是
的语法糖
Del += new Dele(Add);
Dele
是委托类型。在引擎盖下,这是一个 class 和一个 Invoke(int, int)
方法(以及一个 BeginInvoke
/EndInvoke
对)。
当你打电话时:
int ans=Del(4,4);
它是语法糖:
int ans = Del.Invoke(4, 4);
Invoke
方法没有 IL 代码 - 它被声明为 virtual extern
并由运行时处理。当然,实际调用需要的机器码是JIT生成的。
引用自 CLI spec 第 172 页(强调我的):
Delegates shall be declared sealed
, and the only members a delegate shall have are either the first two or all four methods as specified here. These methods shall be declared runtime
and managed
(§II.15.4.3). They shall not have a body, since that body shall be created automatically by the VES.
Other methods available on delegates are inherited from the class System.Delegate
in the Base Class Library (see Partition IV).
here whether the compiler generates the cil code for both true and
false conditions at compiletime or runtime?
两个执行路径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
处看到,其中 Sub
已加载。
运行时唯一发生的事情是创建继承自 MulticastDelegate
的委托,其中创建了三个方法:Invoke
、BeingInvoke
和 EndInvoke
, 如 ECMA-335:
Delegates are created by defining a class that derives from the base
type System.Delegate (see Partition IV). Each delegate type shall
provide a method named Invoke
with appropriate parameters, and each
instance of a delegate forwards calls to its Invoke
method to one or
more static or instance methods on particular objects that are
delegate-assignable-to (§II.14.6.1) the signature of the delegate. The
objects and methods to which it delegates are chosen when the delegate
instance is created. In addition to an instance constructor and an
Invoke method, delegates can optionally have two additional methods:
BeginInvoke
and EndInvoke
. These are used for asynchronous calls.
// 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
引用哪个方法只有在调用时才确定,即在运行时。在我们的例子中,是的,它对优化有一点贡献,因为它只被调用了一次,并且在执行路径中总是只有一个 CIL 代码。希望这就是您正在寻找的答案。
假设有一个委托引用了两个方法,即 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);
这里编译器是在编译时还是运行时为真假条件生成cil代码?
首先,委托没有 IL。
Del+=Add;
是
的语法糖Del += new Dele(Add);
Dele
是委托类型。在引擎盖下,这是一个 class 和一个 Invoke(int, int)
方法(以及一个 BeginInvoke
/EndInvoke
对)。
当你打电话时:
int ans=Del(4,4);
它是语法糖:
int ans = Del.Invoke(4, 4);
Invoke
方法没有 IL 代码 - 它被声明为 virtual extern
并由运行时处理。当然,实际调用需要的机器码是JIT生成的。
引用自 CLI spec 第 172 页(强调我的):
Delegates shall be declared
sealed
, and the only members a delegate shall have are either the first two or all four methods as specified here. These methods shall be declaredruntime
andmanaged
(§II.15.4.3). They shall not have a body, since that body shall be created automatically by the VES. Other methods available on delegates are inherited from the classSystem.Delegate
in the Base Class Library (see Partition IV).
here whether the compiler generates the cil code for both true and false conditions at compiletime or runtime?
两个执行路径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
处看到,其中 Sub
已加载。
运行时唯一发生的事情是创建继承自 MulticastDelegate
的委托,其中创建了三个方法:Invoke
、BeingInvoke
和 EndInvoke
, 如 ECMA-335:
Delegates are created by defining a class that derives from the base type System.Delegate (see Partition IV). Each delegate type shall provide a method named
Invoke
with appropriate parameters, and each instance of a delegate forwards calls to itsInvoke
method to one or more static or instance methods on particular objects that are delegate-assignable-to (§II.14.6.1) the signature of the delegate. The objects and methods to which it delegates are chosen when the delegate instance is created. In addition to an instance constructor and an Invoke method, delegates can optionally have two additional methods:BeginInvoke
andEndInvoke
. These are used for asynchronous calls.
// 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
引用哪个方法只有在调用时才确定,即在运行时。在我们的例子中,是的,它对优化有一点贡献,因为它只被调用了一次,并且在执行路径中总是只有一个 CIL 代码。希望这就是您正在寻找的答案。