C# 11 中的 file local type
Intro
在之前的版本中,我們想要一個類型只在當前的類型中生效,通常我們會在一個類的內部聲明一個 private
的類型以此來控制這個類型的訪問權限,在 C# 11 中引入了一個 file local type,僅在聲明類型的這個文件中可以訪問,這樣我們就可以不用聲明成一個私有類型了,下面就來看個示例吧
Sample
C# 11 新增加了一個 file
關鍵詞,這個關鍵詞也屬于訪問修飾符的一種,用于限定類型只有當前文件有效,使用和其他訪問修飾符類似,使用示例如下:
file?class?FileLocalTypeSample2
{public?int?Age?{?get;?set;?}?=?10;
}
file
本身就是一個訪問修飾符,所以它不能再與其他訪問修飾符一起使用,比如說 public
/internal
/private
等一起使用,否則會看到一個類似下面這樣的一個錯誤
file
是一個類型修飾符,只能用于類型,方法、屬性等成員不能使用,也會報錯
file
不限于 class
也可以用于接口、結構體以及 C# 9/10 引入的 record
file?class?FileLocalTypeSample2
{public?int?Age?{?get;?set;?}?=?10;
}file?record?FileLocalRecord();file?struct?FileLocalStruct
{public?string?RecordName?=>?nameof(FileLocalRecord);
}file?record?struct?FileLocalRecordStruct?{?}file?interface?IAnimal
{string?Name?=>?GetType().Name;
}file?class?Cat?:?IAnimal?{?}class?Dog?:?IAnimal?{?}
當你嘗試在另外一個文件中嘗試訪問 file
修飾的類型時,會訪問不到,比如說上面定義的類型是在 FileLocalTypeSample2.cs
文件中,而下面嘗試訪問則是在 FileLocalTypeSample.cs
文件中,就會報錯,如下所示
那么它是怎么實現的呢,我們可以反編譯一下我們生成的 dll,我們可以找到有一個類型和我們定義的 FileLocalTypeSample2
是一樣的,反編譯結果如下
可以看到,我們用 file
聲明的名稱其實變掉了,實際的類型修飾符是 internal
的,這也意味著我們是有機會來訪問到這個類型的,那我們就來試一下
首先直接引用這個類型,編譯器會報錯,類型不存在
既然不能直接訪問,那我們來嘗試一下反射吧,從下圖可以看到我們成功通過反射獲取到了這一類型
接著我們可以創建一個實例來試試
可以看到我們成功的創建的一個實例,并獲取了其中 Age
屬性的值
More
從上面的示例,我們可以看得出來, file
關鍵詞是一個在編譯器層面實現的特性,本質是由編譯器生成了一個 internal
的類型再加一些編譯檢查來限制只能在聲明的文件中進行訪問,前面雖然我們通過反射的方式創建了file
修飾的類型,但是并不推薦這樣做,隨著編譯器的更新生成的規則一旦變化就可能會 break
有一些不想不暴露出去的類型之前可能是聲明一個 private
?的類型,有了這個特性之后就可以多一種選擇了~~
References
https://github.com/dotnet/csharplang/issues/6011
https://github.com/dotnet/csharplang/blob/main/proposals/file-local-types.md
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp11Sample/FileLocalTypeSample.cs
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp11Sample/FileLocalTypeSample2.cs