解析Visual C# 7.2中的private protected訪問修飾符

去年12月份,隨着Visual Studio 2017 Update 15.5的發佈,Visual C#迎來了它的最新版本:7.2. 在這個版本中,有個讓人難以理解的新特性,就是private protected訪問修飾符(Access Modifier)。至此,C#語言的訪問修飾符有如下幾種:框架

  • private
  • protected
  • public
  • internal
  • internal protected
  • private protected

既然有了private和protected,那麼private protected又是什麼?它跟internal protected又有什麼關係?本文簡單介紹一下。ide

private protected是怎麼回事

在解釋private protected以前,首先讓咱們回顧一下internal protected訪問修飾符。internal protected表示,相同程序集(Assembly)中的其它類型,或者當前類的子類,具備訪問該類中internal protected成員的能力,能夠用下圖表示:ui

image

在上圖中:設計

  • 程序集A中的X類,能夠訪問A類中的Method方法
  • 程序集A中的B類,能夠重載A類中的Method方法,B類中的其它成員也能夠訪問A類中的Method
  • 程序集B中的C類,能夠重載A類中的Method方法,C類中的其它成員也能夠經過base.Method()訪問A類中的Method
  • 程序集B中C類的Method方法重載了A類的Method方法,所以,internal關鍵字被去掉,因而,程序集B中的Y類,沒法訪問C類中的Method方法

所以,internal protected表示internal或者protected。對象

然而,private protected表示,僅有相同程序集(Assembly)中繼承於當前類型的類,才能訪問該類中private protected成員。換句話說,private protected就是訪問者必須在相同程序集中(internal),同時還必須是被訪問類型的子類(protected),能夠用下圖表示:blog

image

所以,private protected表示internal而且protected。繼承

private protected什麼時候使用

理論上講,private protected完善了C#語言的封裝性,提供了另外一層級別的成員訪問保護,聽起來感受讓人費解又沒什麼用。那麼,何時使用這個訪問修飾符呢?現假設你正在設計一個框架,其中有個類,它提供對象存儲功能,它的職責是保存給定的對象,而它的每一種實現都須要依賴於一個對象的序列化機制,好比:開發

public sealed class SerializationHelper
{
    public string Serialze(object s)
    {
        using (var memoryStream = new MemoryStream())
        {
            var serializer = new XmlSerializer(s.GetType());
            serializer.Serialize(memoryStream, s);
            return Encoding.UTF8.GetString(memoryStream.ToArray());
        }
    }
}

public abstract class DataStorage
{
    private readonly SerializationHelper serializer = new SerializationHelper();
    protected SerializationHelper Serializer => serializer;
    protected abstract void SaveObject(object obj);
}

public sealed class InMemoryDataStorage : DataStorage
{
    private readonly List<string> serializedData = new List<string>();
    protected override void SaveObject(object obj) 
        => serializedData.Add(Serializer.Serialze(obj));
}

上面的代碼中,SerializationHelper提供了一種將對象序列化成XML字符串的機制;DataStorage是全部對象數據存儲的基類,它固然也爲其子類提供了一個訪問對象序列化器的方式。因爲這個對象序列化器是提供給其子類調用的,所以,DataStorage中的Serializer屬性是protected的。最後,InMemoryDataStorage繼承了DataStorage,經過調用由基類提供的Serializer屬性,實現了SaveObject方法。字符串

整個實現固然沒有問題。但是,經過審覈全部類型的可見性,咱們發現,咱們不打算將SerializationHelper這個類暴露給外界,也就是不但願其它的程序集可以直接訪問SerializationHelper類,因而,咱們將它設置成internal的。也就是:get

internal sealed class SerializationHelper
{
    public string Serialze(object s)
    {
        using (var memoryStream = new MemoryStream())
        {
            var serializer = new XmlSerializer(s.GetType());
            serializer.Serialize(memoryStream, s);
            return Encoding.UTF8.GetString(memoryStream.ToArray());
        }
    }
}

好了,問題來了,編譯器開始抱怨了,說SerializationHelper類的訪問級別比DataStorage.Serializer屬性的訪問級別要低:

image

道理顯而易見:DataStorage.Serializer屬性在DataStorage的子類中便可訪問,這個子類能夠是在DataStorage所在的程序集中,也能夠是在另外一個程序集中。然而,這個屬性的依賴類型:SerializationHelper類,卻只能在DataStorage所在的程序集中才能被訪問。

因而,能量巨大的private protected閃亮登場。將DataStorage.Serializer屬性的訪問修飾符從protected改成private protected,問題就解決了:

internal sealed class SerializationHelper
{
    public string Serialze(object s)
    {
        using (var memoryStream = new MemoryStream())
        {
            var serializer = new XmlSerializer(s.GetType());
            serializer.Serialize(memoryStream, s);
            return Encoding.UTF8.GetString(memoryStream.ToArray());
        }
    }
}

public abstract class DataStorage
{
    private readonly SerializationHelper serializer = new SerializationHelper();
    private protected SerializationHelper Serializer => serializer;
    protected abstract void SaveObject(object obj);
}

public sealed class InMemoryDataStorage : DataStorage
{
    private readonly List<string> serializedData = new List<string>();
    protected override void SaveObject(object obj) 
        => serializedData.Add(Serializer.Serialze(obj));
}

不過,一旦使用了private protected訪問修飾符,DataStorage.Serializer屬性就只能在DataStorage所在的程序集的子類中訪問了。

private protected如何使用

private protected訪問修飾符是C# 7.2的新特性。自從使用Roslyn編譯器服務的C# 6.0開始,C#編譯器的版本更新就能夠與.NET Framework和Visual Studio的發佈分離開來了。這一點在C# 7.x(包括7.1和7.2)的發佈中逐步顯現出來。在Visual Studio 2017的編譯高級選項中,開發人員能夠很方便地選擇所需的C#版本:

image

如上圖所述,在C#項目上點右鍵,在項目屬性的Build標籤頁中,點擊Advanced按鈕,在Advanced Build Settings對話框中,經過Language version下拉框來選擇所需的C#語言版本。其中:

  • C# latest major version (default):C#最新的主版本,也就是與Visual Studio一塊兒發佈的主要版本,在VS2017上對應C# 7.0
  • C# latest minor version (latest):C#的最新版,一般經過VS2017的升級包得到

要使用private protected訪問修飾符,則須要在此選擇C# latest minor version (latest),或者C# 7.2.

總結

本文對C# 7.2的新特性:private protected訪問修飾符進行了解析,並經過案例來講明它的應用場景以及Visual Studio 2017對於C#新特性的支持。

相關文章
相關標籤/搜索