1 值相等,物件便預設相等?
.net 容器中判斷某個引用類型存在的預設規則是什麼? 判斷指標值是否相等。
private static List<int> list; static void Main(string[] args) { //新建实例instance1 MyObject instance1 = new MyObject(); instance1.Value = 10; //新建list List<MyObject> list = new List<MyObject>(); //引用实例instance1 list.Add(instance1); //新建实例:instance2 MyObject instance2 = new MyObject(); //赋值为instance1.Value instance2.Value = instance1.Value; } }
用到的Model類別:
public class MyObject { public int Value { get; set; } }
下面做1個測試:
//即便Value相等,instance2与instance1的内存地址不相等! bool isExistence1 = list.Contains(instance2); //isExistence1 : false;
這個測試結果是false ,因為它們指向不同的記憶體位址,儘管值相等,這便是「值相等,物件不相等」的情況。
引用類型若是想根據其中的某個屬性值判斷是否相等,那麼需要實作IEquatable介面!
若想繼續看 根據值是否相等 判斷物件是否相等,請參考文章:C# 容器,介面類,效能
2 引用陷阱?
一個物件引用另一個對象,某一個改變,另一個便改變。例如,合併兩個字典,合併結果是對的,但是卻意外改變了原始物件。
在這裡舉個例子:
var dict1 = new Dictionary<string, List<string>>(); dict1.Add("qaz",new List<string>(){"100"});//含有qaz键 dict1.Add("wsx",new List<string>(){"13"}); var dict2 = new Dictionary<string, List<string>>(); dict2.Add("qaz", new List<string>() { "11" });//也含有qaz键 dict2.Add("edc", new List<string>() { "17" }); //合并2个字典到dict var dictCombine = new Dictionary<string, List<string>>(); foreach (var ele in dict1) //拿到dict1 { dictCombine .Add(ele.Key,ele.Value); } foreach (var ele in dict2) //拿到dict2 { if(dictCombine.ContainsKey(ele.Key))//检查重复 dictCombine [ele.Key].AddRange(ele.Value); else { dictCombine .Add(ele.Key,ele.Value); } }
dictCombine的結果正確,{“qaz”, “100”和”11”}, {“wsx ”,”13”},{“edc”,”17”}
但是dict1的結果怎麼樣? 被改變了! dict1意外變成 {“qaz”, “100”和”11”}, {“wsx”,”13”}。 正確的合併,不應該改變dict1!
分析原因
dictCombine首先加入了dict1的鍵值,也就是dictCombine的鍵值都引用了dict1的鍵值; 接下來,再合併dict2時,首先判斷dictCombine中是否包含了dict2的鍵,如果包含,則再往dictCombine的鍵值中添加, 值又引用了同一個對象,也就是在dict1的鍵中添加了這個值。 dictCombine[ele.Key]和dict1[ele.Key]引用是否相等的驗證:
bool flag = object.ReferenceEquals(dictCombine[ele.Key], dict1[ele.Key]);//true
正解
## 避免dictCombine[ele.Key]和dict1[ele .Key]引用相等! ! !Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>(); //先把键都合并到dictCombine中,值都是新创建的 foreach (var key in dict1.Keys) { if (!dictCombine.ContainsKey(key)) dictCombine.Add(key, new List<string>()); } foreach (var key in dict2.Keys) { if (!dictCombine.ContainsKey(key)) dictCombine.Add(key, new List<string>()); } //分别将值添加进去 foreach (var ele in dict1) { dictCombine[ele.Key].AddRange(ele.Value); } foreach (var ele in dict2) { dictCombine[ele.Key].AddRange(ele.Value); }dictCombine合併結果是正確的,且dict1,dict2都未改變!
總結
利用參考相等,帶來了許多好處,例如函數間的參考傳值(by reference)。但是,如果運用不當,也會為我們帶來一些不必要的麻煩。
3 引用不當破壞封裝?
如果將封裝的類別內
私有欄位作為介面方法的傳回值,這種做法會破壞類別的封裝,是特別容易忽略的一個問題。如果忽視這個問題,可能會出現莫名其妙的問題。
如下面的程式碼所示,
public class TestPrivateEncapsulate { private List<object> _refObjs; public List<object> GetRefObjs() { _refObjs = new List<object>(); ... ... //其他逻辑处理计算出来的_refObjs={1,4,2}; return _refObjs; //返回私有字段 } public object GetSumByIterRefObjs() { if (_refObjs == null) return null; foreach (var item in _refObjs) { ...//处理逻辑 } } }現在使用剛才寫的類別TestPrivateEncapsulate,我們先建立一個實例,
TestPrivateEncapsulate test = new TestPrivateEncapsulate();##
List<object> wantedObjs = test.GetRefObjs();## 再##
List<object> sol = wantedObjs; //我们将sol指向wantedObjssol.Add(5); //加入元素5
回傳的預期wantedObjs應該有3個整形類型的元素,1,4,2。
繼續:
test.GetSum();
等我們想回過頭來計算,原來wantedObjs的元素求和:
// 将原来的公有变为私有 private List<object> getRefObjs() { _refObjs = new List<object>(); ... ... //其他逻辑处理计算出来的_refObjs={1,4,2}; return _refObjs; //返回私有字段 } //只带只读的属性 public RefObjs { get { getRefObjs(); return _refObjs; } }
我們意外得到了12,而不是預想中的7。這是為什麼呢?
仔細分析後發現,我們在客戶端調用,sol.Add(5)後,間接的修改了TestPrivateEncapsulate內變數:_refObjs,它由{1,4,2}修改為了{1,4 ,2,5}。
私有變數在客戶端被修改了!這便是介面回傳私有變數帶來的副作用!
正解:
rrreee 設定一個公有字段,僅帶有唯讀屬性,將原來的公有方法GetRefObjs變成私有方法getRefObjs,這樣在客戶端是不可能修改私有欄位的!
總結
物件的屬性值都等,但物件參考不一定相等; 兩個或多個物件都引用某個對象,若這個物件被修改,則所有引用者屬性值也被修改;
成員傳回封裝的引用變量,會破壞封裝。
以上是.NET框架-引用陷阱的程式碼實例分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

C#和.NET提供了強大的功能和高效的開發環境。 1)C#是一種現代、面向對象的編程語言,結合了C 的強大和Java的簡潔性。 2).NET框架是一個用於構建和運行應用程序的平台,支持多種編程語言。 3)C#中的類和對像是面向對象編程的核心,類定義數據和行為,對像是類的實例。 4).NET的垃圾回收機制自動管理內存,簡化開發者的工作。 5)C#和.NET提供了強大的文件操作功能,支持同步和異步編程。 6)常見錯誤可以通過調試器、日誌記錄和異常處理來解決。 7)性能優化和最佳實踐包括使用StringBuild

.NETFramework是一個跨語言、跨平台的開發平台,提供一致的編程模型和強大的運行時環境。 1)它由CLR和FCL組成,CLR管理內存和線程,FCL提供預構建功能。 2)使用示例包括讀取文件和LINQ查詢。 3)常見錯誤涉及未處理異常和內存洩漏,需使用調試工具解決。 4)性能優化可通過異步編程和緩存實現,保持代碼可讀性和可維護性是關鍵。

C#.NET保持持久吸引力的原因包括其出色的性能、豐富的生態系統、強大的社區支持和跨平台開發能力。 1)性能表現優異,適用於企業級應用和遊戲開發;2).NET框架提供了廣泛的類庫和工具,支持多種開發領域;3)擁有活躍的開發者社區和豐富的學習資源;4).NETCore實現了跨平台開發,擴展了應用場景。

C#.NET中的設計模式包括Singleton模式和依賴注入。 1.Singleton模式確保類只有一個實例,適用於需要全局訪問點的場景,但需注意線程安全和濫用問題。 2.依賴注入通過注入依賴提高代碼靈活性和可測試性,常用於構造函數注入,但需避免過度使用導致複雜度增加。

C#.NET在現代世界中廣泛應用於遊戲開發、金融服務、物聯網和雲計算等領域。 1)在遊戲開發中,通過Unity引擎使用C#進行編程。 2)金融服務領域,C#.NET用於開發高性能的交易系統和數據分析工具。 3)物聯網和雲計算方面,C#.NET通過Azure服務提供支持,開發設備控制邏輯和數據處理。

C#.NET開發者社區提供了豐富的資源和支持,包括:1.微軟的官方文檔,2.社區論壇如StackOverflow和Reddit,3.GitHub上的開源項目,這些資源幫助開發者從基礎學習到高級應用,提升編程技能。

C#.NET的優勢包括:1)語言特性,如異步編程簡化了開發;2)性能與可靠性,通過JIT編譯和垃圾回收機制提升效率;3)跨平台支持,.NETCore擴展了應用場景;4)實際應用廣泛,從Web到桌面和遊戲開發都有出色表現。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Dreamweaver Mac版
視覺化網頁開發工具

記事本++7.3.1
好用且免費的程式碼編輯器

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境