最新回應

  • re: 遮蔽與覆寫 to chingchan : 有時候相同的東西(方法)會整理放到父類別(base),然後讓子類....
  • by HOW
  • re: 遮蔽與覆寫 看到這裡還是不懂Override的作用...如果只要顯示子類別的方法,那為何要去繼承父類別? ....
  • by chingchan
  • re: [C#] Code 小技巧 to HOW ?™ : 數值函數幾乎總是比字符串函數更有效率。
  • by HOW ?™
  • re: [C#] Code 小技巧 同事提到,字串是否是空值,用String.Length > 0 效能會比較差,並不會比Stri....
  • by HOW ?™
  • re: [C#]字串 to HOW ?™ : 再補充String串接還有一個方法, ....
  • by HOW ?™
  • re: [C#]字串 補充: + 運算子會預先計算字串長度,判萬有都少記憶體需要配置(深入淺出c# p.741),....
  • by HOW ?™
  • re: [C#]ArrayList初始容量 謝謝Allen老師的提醒,和感謝小賤健講解, 使用ArrayList會將所有要加入的物件都轉....
  • by HOW ?™
  • re: [c#]Local Objects to sholfen : 謝謝您的提醒,看到您的提醒頓時間恍然大悟,自己犯了最基本的錯誤,而在....
  • by HOW ?™
  • re: [c#]Local Objects to 91 : 謝謝您的詳細的講解,Console.Writeline(string)裡面,已....
  • by HOW ?™
  • re: [c#]Local Objects to Bill Chung : 謝謝您提供的資訊與指導,變數在函式裡面為Local Objec....
  • by HOW ?™

比較值是否一樣

前幾天同事不知道要寫什麼功能,突然問我,怎麼比較值物件,我想都沒想就回答他Equals,但他回我說,那不行,我測試過了,不能用,明明就相同也給我跑出false。

當下我就回答他,那我不知道了,之後,review他寫的code,他用Icomparer加泛型寫了一個方法,詢問他才得知這方法主要用於比較string、double、int是否相同,雖然到現在還是搞不懂同事寫這方法的目的是什麼,不過讓我心中一直有個疑問的是Equals為何會明明就相同卻跑出false,因此做了個測試。

我很確定的在同一個class下,使用Equals絕對不會發生同事所說的靈異事件,那會發生應該就是在客戶端,我寫了一個數字跟字串的類別,並在客戶端建立實例,來比較類別方法輸出的整數與字串比較時是否會正常運作。

        static void Main(string[] args)
        {
            Inumber tel = new number();
            tel.SetNumber(028825252);

            Inumber homeTel = new number();
            homeTel.SetNumber(028825252);

            int telA = tel.GetNumber();
            int telB = homeTel.GetNumber();

            if (telA.Equals(telB))
                Console.WriteLine("電話一樣");

            Iname teacher = new name();
            teacher.SetName("Allen");

            Iname student = new name();
            student.SetName("Jerry");

            string teacherName = teacher.GetName();
            string me = student.GetName();

            if (teacherName.Equals(me))
                Console.WriteLine("相等");
            else
                Console.WriteLine("Name不一樣");

            Iname jerry = new name();
            jerry.SetName("jerry");

            Iname how = new name();
            how.SetName("jerry");

            if (jerry.Equals(how))
                Console.WriteLine("同一個物件");
            else
                Console.WriteLine("不同物件");

            Inumber org = new number();
            Inumber home = org;

            Console.WriteLine(org.Equals(home));

        }
    }

    interface Inumber
    {
        void SetNumber(int value);
        int GetNumber();
    }

    interface Iname
    {
        void SetName(string name);
        string GetName();
    }

    class number:Inumber
    {
        private int myNumber;

        public int Number
        {
            get { return myNumber; }
            set { myNumber = value; }
        }

        public void SetNumber(int value)
        {
            this.myNumber = value;
        }

        public int GetNumber()
        {
            return Number;
        }
    }

    class name : Iname
    {
        private string myName;

        public string Name
        {
            get { return myName; }
            set { myName = value; }
        }

        public void SetName(string name)
        {
            this.myName = name;
        }

        public string GetName()
        {
            return Name;
        }
    }

Output :

2012-04-28_234933

 

結論:

我被我同事唬了,但他也自己搞到自己了,可以用很簡單的方式去做,卻自己搞了一個複雜的函式出來,唯一會出現同事所說的情況只有在物件為不同的記憶體位置當中才會出現,但他又說,此函式主要比較string、double、int,看來上班日要好好跟他研究一下,到底是同事唬人,沒測試就說不行,還是另有特殊原因。

更新:

原來同事沒有測試,就認定Equals不行。


如文章有錯誤,煩請告知,新人發帖請多包涵

創用 CC 授權條款
 


DotBlogs Tags: HOW ?™Q&A

關連文章

遮蔽的應用

遮蔽與覆寫

回應

  • # re: 比較物件是否一樣 by 亞斯狼

    在.Net中任何的物件都會去主動繼承Object這個類別, 而這個類別中本身存在一些通用的方法,例如像是: Equals和Hash; 而這兩種方法可以被任何類別進行覆寫, 而通常在對岸的Blog範例中可以觀察到他們都有覆寫這兩個方法的習慣。

     

    再來談談判斷相等這件事。如果沒有特別去覆寫Object這個父類別的Equals和Hash,想當然爾, 當你呼叫這兩種方法時就會自動採用Object中所撰寫的, 但是有的時候你的Equals邏輯可能不同於一般,以你所提的例子來說,你會想要使用Tel和Name來判斷這兩個物件是否相等,這個時候最適當的做法就是覆寫Equals這個方法, 你可以在number和name類別中覆寫,如此一來你就可以很輕鬆的使用Equals來進行判別。

     

    以我所遇到的例子來說, 我想使用Linq To Object中所提供的方法:Except來過濾集合的資料, 卻因為沒有覆寫Hash和Equals而導致結果不符合我的預期, 覆寫過後就一如我所預期般的篩選掉一些重覆資料了。

    2012/4/29 下午 04:31 | 回覆

  • # re: 比較物件是否一樣 by HOW ?™

    to 亞斯狼 :
    LINQ裡的Except是呼叫Hash和Equals來判斷,還不會寫LINQ,先筆記起來,謝謝分享。

    2012/4/29 下午 06:57 | 回覆

  • # re: 比較值是否一樣 by HOW ?™

    我可能把簡單的東西弄得太複雜,同事只是要比對字串與數值是否相同,而我在猜想同事所說雖然輸出值一樣,卻會出現false,是否是因為不同的物件所以不能使用Equals,因此寫了個類別來測試,發現當值一樣,還是會輸出true,因此認為應該是需求不同,或同事沒測試就說不行。

    String物件我確定當值一樣,會指向同一個記憶體位置,所以沒問題,但數值不是class,像int 與 double為struct,不過struct使用Equals的判別就是值是否相同,因此可以斷定可以使用Equals來判斷這三種型別值是否相同。

    有關亞斯狼哥所說的,應該就如同覆寫toString(),來達到不同的效果,記憶中Allen的課程中有提到,為何要覆寫,為何不自行撰寫一個方法,其中有一個原因就如同亞斯狼哥所說,很多時候自行撰寫的物件,在使用這些物件時,經常會用到.NET Framework提供的函式,而某些函式會使用到Equals或toString這類型的方法,因此需要覆寫它,來達到預期中的結果。

     

    2012/4/29 下午 07:59 | 回覆

  • # re: 比較值是否一樣 by 亞斯狼

    string其實是一個有趣的議題, 深入瞭解會發現很多東西。以Java的初級證照SCJP來說,string一直都是熱門考題,由其是你提到的"同一個字串值其記憶體是同一個", 這是因為Compiler會將記憶體分成幾類:

    1. Stack:存放Primitive變數和Struct變數

    2. Heap:存放物件變數

    3. Function:存放類別中所宣告的Function

    4. Global/Static:存放靜態變數

     

    而Heap中.Net又會將大於87K的物件列為超大型物件, 因此,在垃圾回收處理上有不同的做法(這又是個有趣的議題...)。string的值都是存放在Heap區, 而string的值又可以藉由"串接"的方式無限成長, 所以string一直都會是記憶體管理上的熱門話題。

    (關於字串串接的記憶體議題, 可以參考黑暗大的這篇文章http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/12/15/stringbuilder-for-static-string-concate.aspx

    )

     

    以你所遇到的例子來說, 相同值的string會在同一個Heap位址,這是因為.Net和Java有一種管理string的機制稱之為=>String Pool, 其目的在於重覆利用已經產生的字串資料以節省保貴的記憶體,而Pool的大小是可以調整的;也因為這個機制的關係你會看到相同值的字串其Address必定相等。

    2012/5/1 上午 11:38 | 回覆

  • # re: 比較值是否一樣 by 91

    幫忙補充一下,Large object heap的部分,可以參考這個:http://msdn.microsoft.com/zh-tw/magazine/cc534993.aspx

    2012/5/1 下午 12:04 | 回覆

  • # re: 比較值是否一樣 by HOW ?™

    to 亞斯狼 :
    難怪在很多書中,特別都將String類別分為一個章節來解說,而有關記憶體也很感謝您的分享,這部分也一直困擾著我,相信對於這部分深度研究會有更棒的收穫,對於寫碼時,可以更得心應手,另外,相關議題就是參考位置,這部分很重要,卻很多時候會犯了參考位置的錯誤,記得in91哥有寫過相關的一篇文章。

    有關string在相同值時,記憶體當中會使用相同的空間,這部分也是看了msdn才知道,而相關的原理也是亞斯狼解說才了解原來是這樣,再次感謝。

    2012/5/1 下午 04:06 | 回覆

登入後使用進階評論

Please add 1 and 2 and type the answer here: