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

来源:https://www.cnblogs.com/daxnet/archive/2018/03/19/8604801.html
-Advertisement-
Play Games

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


去年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又有什麼關係?本文簡單介紹一下。

private protected是怎麼回事

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

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),可以用下圖表示:

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的。也就是:

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#新特性的支持。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 未對 equals 方法進行重寫,就是用於判斷引用數據類型的變數所指向的對象的地址是否相等,即是否指向同一個對象; == 對於基本數據類型的變數,比較的是變數存儲的值是否相等,而作用於引用類型的變數時,比較的是變數所指向的對象在記憶體中的地址值是否相等。 ...
  • 調用函數 標準的PHP發行包中有1000多個標準函數 假設函數庫已經編譯到安裝發行包中或include()或require()語句包含了相應的函數庫,就可以指定函數名調用函數 計算5的3次方,就可以調用PHP的pow()函數 也可以不把值賦給變數,而是直接輸出 也可以進行拼接 或者使用printf( ...
  • Python很火,我也下了個來耍耍一陣子。可是漸漸地,我已經不滿足於它的基本庫了,我把目光轉到了Numpy~~~~~ 然而想法總是比現實容易,因為我之前下的是Python3.3.x,所有沒有自帶pip!!!(這裡得插一句:很多人以為Python都是自帶pip的,之前的我也是(掩臉笑),印象中是Pyt ...
  • Make a simple custom EventEmitter ...
  • 1,abs 求絕對值 2,max, min求序列最大值與最小值 3,len求列表的長度 4,divmod求商和餘數 5,pow,兩個值,冪運算,3個值,先冪運算,再除以第三個值,求餘數 6,callable測試函數是否可以被調用 7,類型判斷 也可以用isinstance判斷 8,cmp比較字元串大 ...
  • 單例模式 單例模式(Singleton Pattern)是一種常用的軟體設計模式,該模式的主要目的是確保某一個類只有一個實例存在。當希望在整個系統中,某個類只能出現一個實例時,單例對象就能派上用場。 比如,某個伺服器程式的配置信息存放在一個文件中,客戶端通過一個 AppConfig 的類來讀取配置文 ...
  • 因Excel催化劑用了VSTO的開發技術,並且為了最好的用戶體驗,用了Clickonce的佈署方式(無需人工干預自動更新,讓用戶使用如瀏覽器訪問網站一般,永遠是最新的內容和功能)。對安裝過程有一定的難度要求。僅以此文簡單羅列一下,希望能夠給廣大用戶一些實質性的指引(安裝成功過Excel催化劑插件或安 ...
  • 在使用騰訊雲對象存儲之前,公司一直使用的是傳統的FTP的上傳模式,而隨著用戶量的不斷增加,FTP所暴露出來的問題也越來越多,1.傳輸效率低,上傳速度慢。2.時常有上傳其他文件來攻擊伺服器,安全上得不到保障。所以我們在經過慎重考慮覺得使用第三方的雲存儲服務。 在最開始的時候我們在騰訊雲與阿裡雲中選擇, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...