在內部,編譯器應該將lambda表達式轉換爲方法。在那種情況下,這些方法是私有的還是公共的(或其他),是否有可能改變它?C#編譯器是否將lambda表達式視爲公共或私有方法?
回答
這取決於。使用當前版本的Visual Studio,實現lambda表達式的方法從不公開,但它們並不總是私有的。一個簡單的程序來測試lambda表達式的一些版本:
public class Program
{
public static void Main()
{
var program = new Program();
Try("A", program.A);
Try("B", program.B);
Try("C", program.C);
Console.ReadKey();
}
private static void Try(string name, Func<Action> generator)
{
var mi = generator().Method;
Console.WriteLine($"{name}: DeclaringType={mi.DeclaringType}, Attributes={mi.Attributes}");
}
private Action A() =>() => { };
private Action B() =>() => { ToString(); };
private Action C()
{
var c = 1;
return() => c.ToString();
}
}
打印
A: DeclaringType=Scratch.Program+<>c, Attributes=PrivateScope, Assembly, HideBySig
B: DeclaringType=Scratch.Program, Attributes=PrivateScope, Private, HideBySig
C: DeclaringType=Scratch.Program+<>c__DisplayClass4_0, Attributes=PrivateScope, Assembly, HideBySig
A
的拉姆達沒有任何捕獲。它創建爲空閉包類的internal
方法。
B
's lambda captures this
。它創建爲包含類的private
方法。
C
的lambda捕獲c
。它創建爲非空的閉包類的方法internal
。
所有這些都是無證的,並且在過去發生了變化,所以避免依賴它是件好事。重要的是,當你調用匿名方法,它的行爲如指定。如果你需要的不僅僅是這些,你不應該使用匿名方法。根據你以後的情況,你可能仍然可以使用lambda表達式,但是使用表達式樹,或者你可能需要創建常規的命名方法。
很好的答案。但是,捕獲與方法的可見性有什麼關係?如果'A'設置爲'private'(或'B'設置爲'internal'),會出現什麼問題? – haim770
@ haim770包含匿名方法的方法需要能夠訪問該方法以構建委託。如果匿名方法是作爲同一個類的成員創建的,那麼它可以是'private',因爲方法可以訪問他們自己類的私有方法。如果匿名方法是作爲不同類的成員創建的,那麼它至少需要'內部',因爲方法不能訪問其他類的私有方法。提高可視性(使所有內部功能都成爲可能)將成爲可能,但沒有理由讓它看起來比需要的更清晰。 – hvd
請注意,生成的閉包類是私有的,因此,從外部看,該方法是*私有*。 – svick
從通過C#書傑弗裏裏希特
編譯器自動定義在類
一個新的私有方法的CLR ...編譯器會自動爲您
創建方法的名稱...由編譯器生成的匿名方法總是以私有方式結束 ,該方法是靜態的還是非靜態的,具體取決於 關於該方法是否訪問任何實例成員
因此該方法被聲明爲private
或internal
。
例如代碼
class AClass {
public void SomeMethod() {
Action lambda =() => Console.WriteLine("Hello World");
lambda();
}
}
會產生IL聲明作爲
.field private static class [mscorlib]System.Action 'CS$<>9__CachedAnonymousMethodDelegate1'
正如你可以看到它是private static
字段。
不過,請注意lambda表達式可以優化,如果你改變例子
class AClass
{
string a = "Hello World";
public void SomeMethod()
{
Action lambda =() => Console.WriteLine(a);
lambda();
}
}
編譯器優化,並作爲@hvd提到的有有將在所有
IL_0001: ldstr "Hello World"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
沒有拉姆達聲明lambda表達式之間的區別使用來自其周圍環境的參數(閉包情況)或不使用。見:Why do some C# lambda expressions compile to static methods?
所以這個問題只對非關閉情況有意義,當lambda表達式可以轉換成一個委託包裝沒有任何外部依賴。
您可以將生成的類(基本上包裝委託)傳遞給它,它將始終引用定義程序集中生成的委託。所以如果程序集被引用,你可以從任何地方調用它。
剛剛證實,傳遞並執行另一個程序集中定義的動作,雖然Action.Method
本身標記爲內部。
// Main, first assembly
namespace ConsoleApplication1
{
public class B : IB
{
Action _action;
public void AddAction(Action act)
{
_action = act;
}
public void Invoke()
{
Console.WriteLine(_action.Target);
Console.WriteLine("Is public: {0}", _action.Method.IsPublic);
_action();
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
a.AddActionTo(b);
b.Invoke();
Console.ReadKey();
}
}
}
在其它組件:
namespace OtherAssembly
{
public interface IB
{
void AddAction(Action act);
}
public class A
{
public void AddActionTo(IB b)
{
Action act =() => { };
b.AddAction(act);
}
}
}
在內部,編譯器應轉換lambda表達式的方法。
我假設「lambda」是指將lambda轉換爲委託類型。轉換爲表達式樹的Lambdas肯定不是作爲方法生成的。
編譯器確實將這種lambda表達式轉換爲方法,是的。它沒有要求它這樣做,但這樣做很方便。
在這種情況下,這些方法是私有的還是公共的(或其他),是否有可能改變這種情況?
這個問題有些不一致。假設我告訴過你,lambda是一種公共方法。它沒有可從C#訪問的名稱;你將如何利用其公共性?輔助功能修飾符適用於具有名稱的成員。可訪問性域的概念給出了域名名稱在名稱分辨率。
在實踐中,當然編譯器必須爲不可調用的方法的元數據生成一些可訪問性位。在閉包類上生成的方法是內部的,因爲這是使它們可以被驗證的最方便的方法。不使用閉包生成的方法可以是私有的。
再一次,這些都不是必需的,所有這些都是實施細節可能會發生變化。您不應該試圖利用編譯器的代碼生成細節。
- 1. Lambda表達式:編譯器行爲
- 2. 的java lambda表達式沒有編譯
- 3. 與方法公共方法與私有
- 4. 如何將表達式樹編譯爲可調用方法,C#?
- 5. 是否有用於私有公共虛擬方法的用例?
- 6. 以編程方式將變量從公共更改爲私人
- 7. C是否使用lambda表達式?
- 8. 私有或公共MSMQ
- 9. 將lambda表達式翻譯爲表達式樹
- 10. C#編譯器看到Fluent語法或查詢表達式?
- 11. 是否有必要將方法定義爲「公共」?
- 12. Rhino Mocks驗證私有方法是從公共方法調用
- 13. 包私有類中的公共方法
- 14. 繼承和公共/私有方法
- 15. 是否有angular2的流lambda表達式?
- 16. 將C#lambda表達式轉換爲VB
- 17. Lambda表達式不會編譯
- 18. 緩存編譯的lambda表達式
- 19. 是否有可能將方法屬性從公共私有方法更改爲私有方法,並且可以從類內部返回運行時方法?
- 20. 翻譯lambda表達式到方案
- 21. 用方法組替換Lambda表達式時發生編譯器錯誤
- 22. 在C#中是否有方法通過插件覆蓋私有或公共函數?
- 23. 將私有或受保護的方法轉換爲公開
- 24. Lambda表達式來檢查值是否爲空或等於
- 25. 如何將lambda表達式傳遞給期望lambda表達式的方法?
- 26. 是否有編譯爲機器代碼的C C++ C#編譯器
- 27. 爲多個表創建公共相關表是否好方法?
- 28. C++ lambda表達式
- 29. C#Lambda表達式
- 30. 如何檢查C#lambda表達式是否爲「空」?
afaik編譯器創建一個包含此lambda作爲方法的整個類。所以爲了能夠稱呼它,它至少應該是「內部」的。但我不是編譯器專家。 –
@RenéVogt這取決於lambda是否捕獲任何東西。如果沒有,封閉課程就不需要了。 – hvd
如果它是公開的,你會怎樣稱呼它?它沒有任何人知道的名字,除了編譯器。除了包含類以外,任何人都不會使用它,所以沒有理由使它成爲私有的。 –