【C#】 資源共享和實例管理:靜態類,Lazy<T>單例模式,IOC容器Singleton我們該如何選

文章目錄

  • 前言
  • 一、靜態類
    • 1.1 靜態類的特點
    • 1.2 靜態類的使用
    • 1.3 靜態類的缺點
  • 二、單例模式
    • 2.1 Lazy延遲初始化
    • 2.2 Lazy< T>單例模式的使用
    • 2.3 單例模式的特點
  • 三、IOC的Singleton
  • 總結


前言

編寫程序的時候,常常能碰到當某些數據或方法需要被整個程序共享,且不需要多個獨立副本的場景。比如說一個系統配置信息,字符串處理、數據格式化等工具類擴展方法。我們期許這類共享信息,工具類擴展方法能夠開箱即用。常用的解決方案一般有:靜態類,單例模式,IOC容器中的Singleton服務。

  • 比較直接的方法有通過靜態類。靜態屬性存放共享信息,靜態方法實現這類公用的共享方法。

  • 使用普通類的話,也可也通過結合 Lazy< T>實現單例模式,類加載時不創建實例,第一次用訪問點屬性時才創建,多次訪問也不會創建多個實例,保證線程安全。

  • 在現代開發中,可以借用IOC容器實現資源共享。項目啟動的時候向容器里注冊服務,并且將其生命周期設置為singleton,容器第一次解析服務會創建實例并緩存,后續請求容器獲取時直接返回緩存的實例,這樣也是全局唯一。

本文作為一個總結,記錄并對比對這類資源共享和實例管理時采取的解決方案,希望能幫助到大家。


一、靜態類

1.1 靜態類的特點

靜態類作為一種特殊的類類型,定義的時候通過static關鍵詞修飾。本身是不能夠被不能實例化,無法通過new關鍵字創建實例對象。靜態類不能被繼承,也不能實現接口。比起普通類,失去了多態的能力。

靜態類只能包含只能包含靜態成員,一個類被static修飾為靜態類,其內部不能出現非靜態字段,非靜態方法,非靜態屬性。但是普通類里是可以包含靜態字段、靜態方法或者靜態屬性的。

靜態類的生命周期和它所在的AppDomain生命周期一致,在程序加載類的時候被分配到靜態存儲區里(普通類的靜態成員也是被分配到靜態存儲),全局會調用這個唯一對象。

這種全局共享,生命周期與程序一致的特性,并且簡潔的調用方式使其天然容易實現信息共享,和工具擴展方法。

1.2 靜態類的使用

比如這個系統信息配置類,記錄App名稱和版本,在AppDomain內,全局會調用這個唯一對象。
系統信息配置類

public static class AppConfig
{public static string AppName = "我的應用";public static string Version = "1.0.0";
}

系統信息配置信息的調用

var appName = AppConfig.AppName;

比方說接下來的這個靜態工具方法,它要實現的是基于Newtonsoft相關的json序列化和反序列化。通過在靜態類JsonTransfer下面添加靜態擴展方法,其第一個參數指定調用該靜態擴展方法參數的類型,用this指定。

這樣在使用中,就能通過指定類型的對象后面直接調用定義的擴展方法十分的方便。

基于Newtonsoft的工具方法

public static class JsonTransfer
{/// <summary>/// 對象 => JSON字符串/// </summary>/// <param name="obj">對象</param>/// <returns></returns>public static string ToJSON(this object obj, List<JsonSerializedConfig> jsonSerializedConfigs){if (jsonSerializedConfigs.Contains(JsonSerializedConfig.CustomFormatDateTime)){return obj == null ? null : JsonConvert.SerializeObject(obj, Formatting.Indented);}else{return null;}}
}

工具擴展方法調用

WebUser webUser = new WebUser()
{UserID = 1,LoginName = "admin",
};
string? webUserStr = webUser.ToJSON();

1.3 靜態類的缺點

但是靜態成員不支持多態,靜態類無法繼承,也無法實現接口,擴展性很差。

二、單例模式

單例模式的核心是一個類僅僅有唯一實例,并且通過一個pulic的實例屬性這個全局訪問點來供外部函數調用, 它的出現解決了是普通類的對象如何實現僅實例化一次。這一點看上去于靜態類相似,但是單例模式不拘泥于靜態類,可以使普通類也能擁有一個唯一的實例,這點與靜態類截然不同。

2.1 Lazy延遲初始化

前面我們了解到單例模式使普通類也能僅存在一個實例,但是考慮到程序運行的性能更傾向于需要這個類的實例的時候才去實例化這個類,而且在多線程環境下,兩個線程同時請求這個類的實例,如果不加以鎖處理,多線程訪問可能創建多個實例。

這里我們使用.NET提供的延遲初始化的泛型類型Lazy< T>。使用Lazy< T>能將類的實例化延遲到首次需要使用這個對象實例的時候,而不是在聲明這個對象的時候就創建,節省資源,節省不必要的加載時間,提供程序運行性能。

Lazy< T>是通過其Value屬性訪問對象,僅在首次訪問Value的時候,才會實例化對象。 而且Lazy< T> 內置了線程安全支持,多線程同時訪問 Value 時,只有一個線程會執行初始化,其他線程阻塞等待,最終所有線程獲取同一個實例。

2.2 Lazy< T>單例模式的使用

使用Lazy< T>能將類的實例化延遲到首次需要使用這個對象實例的時候,我們可以將一些比如數據庫服務類相關的天然是單例類型的對象,使用Lazy< T>延遲加載,這里拿一個Redis服務類舉例。

我們通過一個Lazy< RedisServer>類型的私有靜態只讀字段存儲唯一實例,并且該RedisServer的構造函數私有,僅允許創建Lazy< T>實例的時候調用。

并且通過一個靜態實例講lazy.Value暴露出去,作為一個訪問點,調用該類實例的各種方法。

Redis服務類

/// <summary>
/// Redis單例服務
/// </summary>
public sealed class RedisServer
{//私有靜態字段,存儲唯一實例private static readonly Lazy<RedisServer> lazy = new Lazy<RedisServer>(() => new RedisServer());/// <summary>/// 靜態實例/// </summary>public static RedisServer Instance { get { return lazy.Value; } }/// <summary>/// Redis連接對象/// </summary>private readonly ConnectionMultiplexer _redis;/// <summary>/// Redis數據庫對象/// </summary>private readonly IDatabase _db;/// <summary>/// Redis鍵前綴/// </summary>private readonly string _keyPrefix = "AlarmCenter_";/// <summary>/// Redis單例服務/// </summary>public RedisServer(){try{ConfigurationOptions config = new ConfigurationOptions(){EndPoints = { "127.0.0.1:6379" }, // Redis服務器地址和端口Password = "eastf@R123",          // Redis密碼AbortOnConnectFail = false,       // 連接失敗時不終止ConnectTimeout = 5000,            // 連接超時時間(毫秒)SyncTimeout = 5000                // 同步操作超時時間(毫秒)};// 創建Redis連接_redis = ConnectionMultiplexer.Connect(config);if (_redis.IsConnected){// 獲取默認數據庫(0)_db = _redis.GetDatabase();}else{Logger.Trace("無法連接到Redis服務器");throw new Exception("無法連接到Redis服務器");}}catch (Exception ex){// 處理連接異常Logger.Trace($"Redis連接錯誤: {ex.Message}");throw;}}/// <summary>/// 獲取Redis數據庫對象/// </summary>public IDatabase GetDatabase(){return _db;}/// <summary>/// 獲取Redis鍵前綴/// </summary>/// <returns></returns>public string GetKeyPrefix(){return _keyPrefix;}public string GetKey(string key){return $"{_keyPrefix}{key}";}/// <summary>/// 關閉Redis連接/// </summary>public void CloseConnection(){_redis?.Close();_redis?.Dispose();}
}

2.3 單例模式的特點

由于單例模式的對象類型并不局限于靜態類,它可以通過接口實現擴展,相比靜態類更加的靈活。

三、IOC的Singleton

在現代的軟件開發框架中,和IOC容器打交道真是家常便飯,其服務的注入分三種生命周期,分別是:Singleton,Socpe,Transient。

往IOC容器里注冊一個Singleton生命周期的服務時,在首次解析到該服務的時候,會創建一個這個服務的實例,并且緩存下來。后續所有對該服務的請求都會返回這個緩存,并且會隨著容器的銷毀自動實現IDisposable,一并被GC回收。

比如我們還是編寫一個Redis服務類,這次不需要編寫額外的單例相關的代碼。該服務類不需要關心類的實例化,線程安全,性能開銷。
Redis服務類

services.AddSingleton<IRedisService, RedisService>();

總結

  • 簡單工具類/配置,這些可以考慮靜態類,編寫和使用起來很簡潔性。
  • 復雜的創建邏輯,并且要考慮到擴展,可以選擇 Lazy< T>單例模式,兼顧靈活性與性能。
  • .NET Core開發環境下首選IOC Singleton,符合面向接口編程和低耦合原則。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/96270.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/96270.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/96270.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MySQL——存儲引擎、索引

一、存儲引擎1.MySQL體系結構2.存儲引擎簡介存儲引擎就是儲存數據、建立索引、更新/查詢數據等技術的實現方式。儲存引擎是基于表的&#xff0c;而不是基于庫的&#xff0c;所以存儲引擎也可被稱為表類型建表語句&#xff1a;查詢數據庫支持的儲存引擎&#xff1a;show engines…

機器學習01——機器學習概述

上一章&#xff1a;機器學習核心知識點目錄 下一章&#xff1a;機器學習02——模型評估與選擇 機器學習實戰項目&#xff1a;【從 0 到 1 落地】機器學習實操項目目錄&#xff1a;覆蓋入門到進階&#xff0c;大學生就業 / 競賽必備 文章目錄一、參考書推薦二、機器學習的基本概…

Shell編程:檢測主機ip所在網段內其他在線ip

一、邏輯設計獲取本機 ip 及 網段循環檢測網段內所有 ip判斷 ping 結果&#xff0c;符合條件的輸出相關信息二、代碼展示#!/bin/bash#獲取本機ip local_iphostname -I #local_ipip addr| grep "inet "|grep -v 127.0.0.1| awk {print $2}#獲取本機網段 networkecho $…

Windows安裝Chroma DB

安裝步驟 安裝python 3.8或以上的版本創建虛擬環境&#xff1a;python -m venv chroma_env激活虛擬環境&#xff1a;.\chroma_env\Scripts\activate安裝Chroma DB&#xff1a;pip install chromadb(可選)安裝擴展功能&#xff1a;pip install sentence-transformers pypdf tikt…

李彥宏親自說

昨天&#xff0c;李彥宏親自說&#xff1a;百度的數字人直播以假亂真&#xff0c;很多人是看不出這是數字人&#xff0c;而且轉化率很高”這幾個月百度一直在推“數字人”不再強調“大模型”了。數字人是AI落地最適合企業的一款產品&#xff0c;一般用于客服、面試、直播帶貨等…

JS 中bind、call、apply的區別以及手寫bind

1.作用call、apply、bind作用是改變函數執行的上下文&#xff0c;簡而言之就是改變函數運行時的this指向那么什么情況下需要改變this的指向呢&#xff1f;下面舉個例子var name "lucy"; var obj {name: "martin",say: function () {console.log(this.nam…

vue2(7)-單頁應用程序路由

1.單頁應用程序如 單頁&#xff1a;網易云&#xff0c;多頁&#xff1a;京東單頁應用程序&#xff0c;之所以開發效率高&#xff0c;性能高&#xff0c;用戶體驗好最大的原因是&#xff1a;頁面按需更新 要按需更新&#xff0c;就要明確訪問路徑和組件的關系這時候就要用…

vue中通過heatmap.js實現熱力圖(多個熱力點)熱區展示(帶鼠標移入彈窗)

直接上完整代碼&#xff01;記錄實現方式 注意heatmap.min.js需要通過heatmap.js提供的下載地址進行下載&#xff0c;地址放在下邊 url&#xff1a;heatmap GIT地址 <template><div class"heatmap-view" ref"heatmapContainer"></div&g…

配置Kronos:k線金融大模型

github地址 網頁btc預測demo使用的Kronos-mini模型 huggingface的倉庫 文章目錄配置環境安裝python環境獲取市場數據的庫通過webui使用example中的例子prediction_example.py補充說明根據原例優化的代碼CryptoDataFetcher單幣對多周期預測配置環境 使用conda的環境. 首先進行換…

【Deep Learning】Ubuntu配置深度學習環境

【start: 250715】 文章目錄ubuntu與深度學習安裝cuda查看顯卡信息&#xff08;nvidia-smi&#xff09;升級驅動下載cuda安裝conda安裝anaconda默認指向自己的conda初始化conda確認 conda.sh 被加載安裝cuda-toolkit直接安裝cuda-toolkit&#xff08;高級的&#xff09;安裝高于…

車載數據采集(DAQ)解析

<摘要> 車載數據采集&#xff08;DAQ&#xff09;軟件模塊是現代汽車電子系統的核心組件&#xff0c;負責實時采集、處理、記錄和傳輸車輛運行數據。本文系統解析了DAQ模塊的開發&#xff0c;涵蓋其隨著汽車智能化演進的歷史背景&#xff0c;深入闡釋了信號、協議、緩存等…

強化學習框架Verl運行在單塊Tesla P40 GPU配置策略及避坑指南

1.前言 由于比較窮,身邊只有1塊10年前的Tesla P40 GPU卡(2016年9月發布),想利用起來學習強化學習框架Verl。程序員學習開源代碼,大部分人的第一直覺不是分析模塊組成,而是跑起來試試,然后去debug一下后面的運行邏輯。 由于在官方部署指導文檔中并未指明跑通Verl的最低…

leetcode169.多數元素

題目描述給定一個大小為 n 的數組 nums &#xff0c;返回其中的多數元素。多數元素是指在數組中出現次數 大于 ? n/2 ? 的元素。你可以假設數組是非空的&#xff0c;并且給定的數組總是存在多數元素。題目解法博耶-摩爾多數投票算法&#xff08;英語&#xff1a;Boyer–Moore…

基于機器學習的P2P網貸平臺信用違約預測模型

使用平臺提供的借款人信息&#xff08;年齡、收入、歷史信用等&#xff09;和借款信息&#xff0c;構建一個二分類模型來預測借款人是否會違約。重點解決類別不平衡問題和模型可解釋性。邏輯回歸、隨機森林、XGBoost、SMOTE過采樣、模型評估&#xff08;AUC, KS, F1-Score&…

豆瓣網影視數據分析與應用

源碼鏈接&#xff1a;點擊下載源碼 相關文檔&#xff1a;點擊下載相關文檔 摘 要 隨著互聯網的快速發展&#xff0c;豆瓣網作為一個綜合性的影視評分和評論平臺&#xff0c;積累了大量的用戶數據&#xff0c;這些數據為影視分析提供了豐富的素材。借助Hadoop這一大數據處理框…

四、計算機網絡與分布式系統(中)

一、局域網與廣域網1、局域網&#xff08;1&#xff09;定義將有限地理范圍內的多臺計算機通過傳輸媒體連接&#xff0c;借助網絡軟件實現設備間通信與資源共享的通信網絡&#xff08;2&#xff09;特點1.地理范圍小&#xff1a;通常為數百米至數公里內。2.傳輸速率高&#xff…

Python 面向對象實戰:私有屬性與公有屬性的最佳實踐——用線段類舉例

描述 在繪圖軟件、GIS、CAD 或簡單的圖形編輯器中&#xff0c;線段&#xff08;Segment&#xff09;是非常基礎的對象。每個線段有兩個端點&#xff08;x1,y1&#xff09;和&#xff08;x2,y2&#xff09;。在實現時我們通常希望&#xff1a; 封裝端點數據&#xff08;防止外部…

流式細胞術樣本處理全攻略(一):組織、血液、體液制備方法詳解

摘要 流式細胞術作為多參數、高通量的細胞分析技術,在細胞表型鑒定、免疫反應研究、疾病機制探索及藥物效果評估中發揮關鍵作用。而樣本制備是流式實驗成功的核心前提,需將不同來源樣本處理為單顆粒懸液,并最大程度減少細胞死亡與碎片干擾。本文針對組織、外周血 / 骨髓、體…

【C#】理解.NET內存機制:堆、棧與裝箱拆箱的底層邏輯及優化技巧

文章目錄前言一、棧與堆1.1 棧&#xff08;Stack&#xff09;1.1.1 基本信息1.1.2 特點1.2 堆&#xff08;Heap&#xff09;1.2.1 基本信息1.2.2 特點1.3 從代碼中窺見堆棧二、裝箱與拆箱2.1 裝箱2.2 拆箱2.3 如何避免不必要的裝箱與拆箱2.3.1 泛型集合2.3.2 泛型參數總結前言 …

人工智能學習:Transformer結構中的子層連接(Sublayer Connection)

Transformer結構中的子層連接(Sublayer Connection) 一、子層連接介紹 概念 子層連接(Sublayer Connection),也稱為殘差連接(Residual Connection),是Transformer模型中的一個關鍵設計,用于將多個子層(如自注意力層和前饋全連接層)組合在一起。它通過殘差連…