我试过反汇编C#创建的可执行文件,但我无法得出结论。我想知道的是,如果CLR c#的代表真的是特殊实体或只是编译器糖吗?
我问这个是因为我正在实现一种编译成C#的语言,对于我来说,将匿名函数编译为类而不是代理将会更有趣。但是我不想使用后来我会后悔的设计,因为它们可能在内存上更重(我想起Java的PermGen是基于我的问题。尽管我知道CLR没有这样的东西。)< / p>
谢谢!
- 修改
更清楚一点,我想知道是否存在(和有什么)之间的区别:
void Main()
{
Func<int, int, int> add = delegate(int a, int b) {return a + b;};
}
,例如
class AnonFuncion__1219023 : Fun3
{
public override int invoke(int a, int b)
{
return a + b;
}
}
- 编辑
我认为:
之间可能存在很大差异class Program
{
static int add(int a, int b)
{
return a + b;
}
static void Main()
{
Func<int, int, int> add = Program.add;
}
}
和
class Function__432892 : Fun3
{
public override int invoke(int a, int b)
{
return Program.add(a, b);
}
}
我在某处读到,语法Func<int, int, int> add = Program.add;
只是Func<int, int, int> add = delegate(int a, int b) { return Program.add; };
的糖。但我真的不知道这是否真的如此。
我还可以看到C#编译器已经缓存了所有这些实例,因此它们只构造了一次。不过,我可以对我的编译器做同样的事情。
答案 0 :(得分:7)
我很惊讶你无法通过反汇编可执行文件得出结论。让我们来看看非常简单的事情:
using System;
class A
{
int _x;
public A(int x)
{
_x = x;
}
public void Print(int y)
{
Console.WriteLine(_x + y);
}
}
interface IPseudoDelegateVoidInt
{
void Call(int y);
}
class PseudoDelegateAPrint : IPseudoDelegateVoidInt
{
A _target;
public PseudoDelegateAPrint(A target)
{
_target = target;
}
public void Call(int y)
{
_target.Print(y);
}
}
class Program
{
delegate void RealVoidIntDelegate(int x);
static void Main()
{
A a = new A(5);
IPseudoDelegateVoidInt pdelegate = new PseudoDelegateAPrint(a);
RealVoidIntDelegate rdelegate = new RealVoidIntDelegate(a.Print);
pdelegate.Call(2);
rdelegate(2);
}
}
如果我们反汇编这个,我们得到
// Microsoft (R) .NET Framework IL Disassembler. Version 4.0.30319.1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly del
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module del.exe
// MVID: {87A2A843-A5F2-4D40-A96D-9940579DE26E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x0000000000B60000
// =============== CLASS MEMBERS DECLARATION ===================
.class private auto ansi beforefieldinit A
extends [mscorlib]System.Object
{
.field private int32 _x
.method public hidebysig specialname rtspecialname
instance void .ctor(int32 x) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld int32 A::_x
IL_000f: nop
IL_0010: ret
} // end of method A::.ctor
.method public hidebysig instance void
Print(int32 y) cil managed
{
// Code size 16 (0x10)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld int32 A::_x
IL_0007: ldarg.1
IL_0008: add
IL_0009: call void [mscorlib]System.Console::WriteLine(int32)
IL_000e: nop
IL_000f: ret
} // end of method A::Print
} // end of class A
.class interface private abstract auto ansi IPseudoDelegateVoidInt
{
.method public hidebysig newslot abstract virtual
instance void Call(int32 y) cil managed
{
} // end of method IPseudoDelegateVoidInt::Call
} // end of class IPseudoDelegateVoidInt
.class private auto ansi beforefieldinit PseudoDelegateAPrint
extends [mscorlib]System.Object
implements IPseudoDelegateVoidInt
{
.field private class A _target
.method public hidebysig specialname rtspecialname
instance void .ctor(class A target) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: stfld class A PseudoDelegateAPrint::_target
IL_000f: nop
IL_0010: ret
} // end of method PseudoDelegateAPrint::.ctor
.method public hidebysig newslot virtual final
instance void Call(int32 y) cil managed
{
// Code size 15 (0xf)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class A PseudoDelegateAPrint::_target
IL_0007: ldarg.1
IL_0008: callvirt instance void A::Print(int32)
IL_000d: nop
IL_000e: ret
} // end of method PseudoDelegateAPrint::Call
} // end of class PseudoDelegateAPrint
.class private auto ansi beforefieldinit Program
extends [mscorlib]System.Object
{
.class auto ansi sealed nested private RealVoidIntDelegate
extends [mscorlib]System.MulticastDelegate
{
.method public hidebysig specialname rtspecialname
instance void .ctor(object 'object',
native int 'method') runtime managed
{
} // end of method RealVoidIntDelegate::.ctor
.method public hidebysig newslot virtual
instance void Invoke(int32 x) runtime managed
{
} // end of method RealVoidIntDelegate::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult
BeginInvoke(int32 x,
class [mscorlib]System.AsyncCallback callback,
object 'object') runtime managed
{
} // end of method RealVoidIntDelegate::BeginInvoke
.method public hidebysig newslot virtual
instance void EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
{
} // end of method RealVoidIntDelegate::EndInvoke
} // end of class RealVoidIntDelegate
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 45 (0x2d)
.maxstack 3
.locals init (class A V_0,
class IPseudoDelegateVoidInt V_1,
class Program/RealVoidIntDelegate V_2)
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: newobj instance void A::.ctor(int32)
IL_0007: stloc.0
IL_0008: ldloc.0
IL_0009: newobj instance void PseudoDelegateAPrint::.ctor(class A)
IL_000e: stloc.1
IL_000f: ldloc.0
IL_0010: ldftn instance void A::Print(int32)
IL_0016: newobj instance void Program/RealVoidIntDelegate::.ctor(object,
native int)
IL_001b: stloc.2
IL_001c: ldloc.1
IL_001d: ldc.i4.2
IL_001e: callvirt instance void IPseudoDelegateVoidInt::Call(int32)
IL_0023: nop
IL_0024: ldloc.2
IL_0025: ldc.i4.2
IL_0026: callvirt instance void Program/RealVoidIntDelegate::Invoke(int32)
IL_002b: nop
IL_002c: ret
} // end of method Program::Main
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Program::.ctor
} // end of class Program
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\logan\del.res
正如您所看到的,RealVoidIntDelegate变成了“只是”另一个类。他们称之为Invoke
而不是Call
,并且他们没有使用界面,但没有涉及特殊说明,它是相同的基本想法。
为了详细阐述“轻量级”的概念,委托的重量不比类轻,因为给定的委托是一个类。特别是在函数文字语法的情况下,它们的重量确实不能轻得多。但是,对于“使用这些args在此对象上调用此方法”,在编译为C#时,调用和创建给定委托的情况可能比本地代理更轻,但
答案 1 :(得分:3)
代表是课程。 .NET编译器为每个委托创建一个类型,代码必须实例化一个委托。
在任何情况下,性能差异都可以忽略不计,除非您正在撰写非常罕见的应用,其中每纳秒都很重要。
答案 2 :(得分:3)
这里没有什么大不了的。引导Jon Skeet ......
如果您查看C# Specification的6.5.3,您将看到编译器如何处理匿名委托的几个示例。简要总结:
IF 匿名方法不会捕获外部变量,
那么它可以在封闭类型上创建为静态方法。
IF 匿名方法引用封闭类型的成员,例如this.x
那么它可以作为封闭类型的实例方法创建。
IF 匿名方法捕获局部变量,
THEN 它可以在封闭类型中创建为嵌套类型,实例变量与捕获的变量匹配,以及与委托类型匹配的实例方法。
最后一个示例更复杂,查看代码更容易。看看你自己,我认为它将消除所有的猜测。
答案 3 :(得分:1)
两者之间的差异似乎很小,顶部代码段有效地编译成与底部代码段中的内容几乎相同的内容。
答案 4 :(得分:1)
除了元数据之外,一旦获得所有内容,就没有类似的东西 JIT编译。对象的运行时表示是一个大字节数组 足以存储该类的所有字段 它是基类,加上一个存储一个的对象头 哈希码,数字类型标识符和指向共享的指针 保存虚函数覆盖地址的v-table。
委托是一个对象,其类派生自System.Delegate。它存储一组对象和函数指针对。
匿名函数是一个没有名称的函数。但是,它们也是 通常与称为闭包的对象相关联,该对象包含创建指向匿名函数的“匿名委托”的包含方法中定义的所有参数和局部。 (实际上它通常只包含那些实际访问过的变量。)
在任何情况下,将堆栈变量移动到堆都允许匿名委托实现它的定义堆栈框架。
将匿名函数与其闭包关联起来的最简单方法是使其成为编译器生成的闭包类的方法。
因此,如果你有词法闭包,你必须(至少在某些情况下)使用一个类来实现匿名函数。
如果你没有词法闭包,那么你可以发出“匿名函数”作为 带有编译器生成名称的常规函数,在声明它的方法旁边。在语言支持词法闭包的情况下,这也是一个有用的优化,但不需要。
一般情况下,如果没有闭包支持,匿名函数就无用了,所以如果不支持闭包,我就不会用你的语言包含它们。