首頁 後端開發 C#.Net教程 C#reference的3個思考詳細介紹

C#reference的3個思考詳細介紹

Mar 04, 2017 am 10:53 AM

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,這樣在客戶端是不可能修改私有欄位的!

總結

物件的屬性值都等,但物件參考不一定相等; 兩個或多個物件都引用某個對象,若這個物件被修改,則所有引用者屬性值也被修改;
成員傳回封裝的引用變量,會破壞封裝。

 以上就是C#reference的3個思考詳細介紹的內容,更多相關內容請關注PHP中文網(www.php.cn)!


#

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1274
29
C# 教程
1256
24
使用 C# 的活動目錄 使用 C# 的活動目錄 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在這裡,我們討論 Active Directory 在 C# 中的介紹和工作原理以及語法和範例。

C# 中的隨機數產生器 C# 中的隨機數產生器 Sep 03, 2024 pm 03:34 PM

C# 隨機數產生器指南。在這裡,我們討論隨機數產生器的工作原理、偽隨機數和安全數的概念。

C# 資料網格視圖 C# 資料網格視圖 Sep 03, 2024 pm 03:32 PM

C# 資料網格視圖指南。在這裡,我們討論如何從 SQL 資料庫或 Excel 檔案載入和匯出資料網格視圖的範例。

C# 中的階乘 C# 中的階乘 Sep 03, 2024 pm 03:34 PM

C# 階乘指南。這裡我們討論 C# 中階乘的介紹以及不同的範例和程式碼實作。

c#多線程和異步的區別 c#多線程和異步的區別 Apr 03, 2025 pm 02:57 PM

多線程和異步的區別在於,多線程同時執行多個線程,而異步在不阻塞當前線程的情況下執行操作。多線程用於計算密集型任務,而異步用於用戶交互操作。多線程的優勢是提高計算性能,異步的優勢是不阻塞 UI 線程。選擇多線程還是異步取決於任務性質:計算密集型任務使用多線程,與外部資源交互且需要保持 UI 響應的任務使用異步。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在這裡,我們討論 C# 中模式的介紹和前 3 種類型,以及其範例和程式碼實作。

C# 中的質數 C# 中的質數 Sep 03, 2024 pm 03:35 PM

C# 質數指南。這裡我們討論c#中素數的介紹和範例以及程式碼實作。

xml怎麼改格式 xml怎麼改格式 Apr 03, 2025 am 08:42 AM

可以採用多種方法修改 XML 格式:使用文本編輯器(如 Notepad )進行手工編輯;使用在線或桌面 XML 格式化工具(如 XMLbeautifier)進行自動格式化;使用 XML 轉換工具(如 XSLT)定義轉換規則;或者使用編程語言(如 Python)進行解析和操作。修改時需謹慎,並備份原始文件。

See all articles