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#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

C#在.NET中的編程過程包括以下步驟:1)編寫C#代碼,2)編譯為中間語言(IL),3)由.NET運行時(CLR)執行。 C#在.NET中的優勢在於其現代化語法、強大的類型系統和與.NET框架的緊密集成,適用於從桌面應用到Web服務的各種開發場景。

C#是一種現代、面向對象的編程語言,由微軟開發並作為.NET框架的一部分。 1.C#支持面向對象編程(OOP),包括封裝、繼承和多態。 2.C#中的異步編程通過async和await關鍵字實現,提高應用的響應性。 3.使用LINQ可以簡潔地處理數據集合。 4.常見錯誤包括空引用異常和索引超出範圍異常,調試技巧包括使用調試器和異常處理。 5.性能優化包括使用StringBuilder和避免不必要的裝箱和拆箱。

C#.NET應用的測試策略包括單元測試、集成測試和端到端測試。 1.單元測試確保代碼的最小單元獨立工作,使用MSTest、NUnit或xUnit框架。 2.集成測試驗證多個單元組合的功能,常用模擬數據和外部服務。 3.端到端測試模擬用戶完整操作流程,通常使用Selenium進行自動化測試。

C#高級開發者面試需要掌握異步編程、LINQ、.NET框架內部工作原理等核心知識。 1.異步編程通過async和await簡化操作,提升應用響應性。 2.LINQ以SQL風格操作數據,需注意性能。 3..NET框架的CLR管理內存,垃圾回收需謹慎使用。

C#.NET面試問題和答案包括基礎知識、核心概念和高級用法。 1)基礎知識:C#是微軟開發的面向對象語言,主要用於.NET框架。 2)核心概念:委託和事件允許動態綁定方法,LINQ提供強大查詢功能。 3)高級用法:異步編程提高響應性,表達式樹用於動態代碼構建。

C#.NET是構建微服務的熱門選擇,因為其生態系統強大且支持豐富。 1)使用ASP.NETCore創建RESTfulAPI,處理訂單創建和查詢。 2)利用gRPC實現微服務間的高效通信,定義和實現訂單服務。 3)通過Docker容器化微服務,簡化部署和管理。

C#和.NET的安全最佳實踐包括輸入驗證、輸出編碼、異常處理、以及身份驗證和授權。 1)使用正則表達式或內置方法驗證輸入,防止惡意數據進入系統。 2)輸出編碼防止XSS攻擊,使用HttpUtility.HtmlEncode方法。 3)異常處理避免信息洩露,記錄錯誤但不返回詳細信息給用戶。 4)使用ASP.NETIdentity和Claims-based授權保護應用免受未授權訪問。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

SublimeText3 Linux新版
SublimeText3 Linux最新版

WebStorm Mac版
好用的JavaScript開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。