c#编译器由于缓存代理而奇怪的行为
假设我有以下程序:
static void SomeMethod(Func<int,int> otherMethod) { otherMethod(1); } static int OtherMethod(int x) { return x; } static void Main(string[] args) { SomeMethod(OtherMethod); SomeMethod(x => OtherMethod(x)); SomeMethod(x => OtherMethod(x)); } 我不明白编译的il代码(它使用太多的代码).这是简化版本: class C { public static C c; public static Func<int,int> foo; public static Func<int,int> foo1; static C() { c = new C(); } C(){} public int b(int x) { return OtherMethod(x); } public int b1(int x) { return OtherMethod(x); } } static void Main() { SomeMethod(new Func<int,int>(OtherMethod)); if (C.foo != null) SomeMethod(C.foo) else { C.foo = new Func<int,int>(c,C.b) SomeMethod(C.foo); } if (C.foo1 != null) SomeMethod(C.foo1) else { C.foo1 = new Func<int,C.b1) SomeMethod(C.foo1); } } 为什么编译器不会创建静态等效的方法b / b1? Equal表示它们具有相同的代码 解决方法
你的问题是:为什么编译器没有意识到这两行
SomeMethod(x => OtherMethod(x)); SomeMethod(x => OtherMethod(x)); 是一样的,写为 if ( delegate is not created ) create the delegate and stash it away SomeMethod( the delegate ); SomeMethod( the delegate ); ?那么让我以几种方式回答这个问题. 首先,编译器允许进行优化?是.该规范呼吁,C#编译器允许使两个完全相同的东西的lambdas成为一个委托.实际上,你可以看到它已经完成了这个优化:它创建了每个代理一次,并将其保存起来,以便在再次调用代码时不必再创建它.请注意,在代码只被调用一次的情况下,这是浪费内存. 其次,编译器是否需要进行缓存优化?不,规范要求编译器只允许进行优化,但不是必需的. 编译器是否需要进行优化?显然不是,因为没有.允许,也可能是将来版本的编译器.编译器是开源的;如果您关心此优化,请写入并提交拉取请求. 第三,是否可以进行优化?是.编译器可以使用同一方法中出现的所有成对的lambdas,将它们编译为内部树形格式,并进行树比较以查看它们是否具有相同的内容,然后为两者生成相同的静态后台字段. 所以现在我们有一个情况:编译器被允许进行特定的优化,而不是.你问“为什么不”?这是一个容易解答的问题:所有的优化都没有实现,直到有人花费了相当多的时间和精力: >仔细设计优化:在什么条件下优化触发而不触发?优化应该如何通用?你建议他们检测到类似的lambda体,但为什么要停在那里?你有两个相同的代码语句,所以为什么不为这些语句生成一次而不是两次的代码?如果你有一连串的陈述呢?这里有大量的设计工作. 你想要的优化根本不符合条件.没有人写这样的代码.如果他们这样做,他们关心它复制了一个对象,他们可以很容易地修复它.因此,优化优化了不存在的代码,以获得在程序将分配的数百万和数百万个对象中构建单个对象的“赢”.不值得. 但是再一次,如果你认为是这样,请继续执行并提交一个请求.请务必提交上述调查结果,因为那些是真实的工作.实施通常是在功能上花费的总计努力的最小部分;这就是为什么C#是一个成功的语言. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |