c# – 為什麼lambda表示式不是“interned”?
字串是引用型別,但它們是不可變的.這允許他們被編譯器實習;在任何地方出現相同的字串文字,可以引用相同的物件.
代表也是不可變的參考型別. (使用=運算子向多播委託中新增一個方法構成賦值;這不是可變性.)而且,像字串一樣,使用lambda表示式,以程式碼形式表示代理的“文字”方式,例如:
Func<int> func = () => 5;
該語句的右側是一個型別為Func<int>;但是我無法顯式地呼叫Func<int>建構函式(也不會發生隱式轉換).所以我認為這本質上是一個字面意思.我在這裡誤解了我對“文字”的定義嗎?
無論如何,這是我的問題.如果我有兩個變數,例如Func<int>鍵入,並且我將相同的lambda表示式分配給兩者:
Func<int> x = () => 5; Func<int> y = () => 5;
…什麼阻止編譯器將它們視為相同的Func<int>目的?
我問,因為ofollow,noindex" target="_blank">C# 4.0 language specification 的6.5.1節明確規定:
Conversions of semantically identicalanonymous functions with the same(possibly empty) set of captured outervariable instances to the samedelegate types are permitted (but notrequired) to return the same delegateinstance. The term semanticallyidentical is used here to mean thatexecution of the anonymous functionswill, in all cases, produce the sameeffects given the same arguments.
當我讀到它時,我感到驚訝如果這個行為是明確允許的,我會期望它被實現.但似乎不是這樣.這實際上讓很多開發者陷入困境,尤其是.當lambda表示式被用來成功附加事件處理程式,而無法刪除它們.例如:
class EventSender { public event EventHandler Event; public void Send() { EventHandler handler = this.Event; if (handler != null) { handler(this, EventArgs.Empty); } } } class Program { static string _message = "Hello, world!"; static void Main() { var sender = new EventSender(); sender.Event += (obj, args) => Console.WriteLine(_message); sender.Send(); // Unless I'm mistaken, this lambda expression is semantically identical // to the one above. However, the handler is not removed, indicating // that a different delegate instance is constructed. sender.Event -= (obj, args) => Console.WriteLine(_message); // This prints "Hello, world!" again. sender.Send(); } }
是否有任何理由為什麼這種行為 – 一個委託例項的語義相同的匿名方法 – 沒有實現?
你被誤認為是一個字面意思.它只是一個可轉換為委託型別的表示式.
現在對於“interning”部分 – 一些lambda表示式被快取,因為對於一個單一的lambda表示式,有時可以建立和重用一個例項,但是經常會遇到這行程式碼.有些不是這樣對待的:它通常取決於lambda表示式是否捕獲任何非靜態變數(無論是通過“this”還是通過本方法).
以下是此快取的示例:
using System; class Program { static void Main() { Action first = GetFirstAction(); first -= GetFirstAction(); Console.WriteLine(first == null); // Prints True Action second = GetSecondAction(); second -= GetSecondAction(); Console.WriteLine(second == null); // Prints False } static Action GetFirstAction() { return () => Console.WriteLine("First"); } static Action GetSecondAction() { int i = 0; return () => Console.WriteLine("Second " + i); } }
在這種情況下,我們可以看到第一個動作被快取(或者至少有兩個相同的代理被生成,實際上Reflector顯示它真的被快取在靜態域中).第二個操作為GetSecondAction的兩次呼叫建立了兩個不等的Action例項,這就是為什麼“second”在結尾是非空的.
在程式碼中出現不同位置但具有相同原始碼的Interning lambdas是另一回事.我懷疑這樣做是很複雜的(畢竟,相同的原始碼可能意味著不同的地方不同),我一定不想依靠它發生.如果不值得依靠的話,編譯器團隊的工作很多,我不認為這是他們花時間的最好方法.
http://stackoverflow.com/questions/4807808/why-are-lambda-expressions-not-interned