C#學習記錄:編寫高品質代碼改善整理建議9-15

來源:互聯網
上載者:User
9、習慣重載運算子

在構建自己的類型時,始終應該考慮是否可以使用運算子多載

10、建立對象時需要考慮是否實現比較子

如果需要排序,有兩種比較子實現

class FirstType : IComparable<FirstType>{    public string name;    public int age;    public FirstType(int age)    {        name = "aa";        this.age = age;    }    public int CompareTo(FirstType other)    {        return other.age.CompareTo(age);    }}static void Main(string[] args){    FirstType f1 = new FirstType(3);    FirstType f2 = new FirstType(5);    FirstType f3 = new FirstType(2);    FirstType f4 = new FirstType(1);    List<FirstType> list = new List<FirstType>    {        f1,f2,f3,f4    };    list.Sort();    foreach (var item in list)    {        Console.WriteLine(item);    }}

或者第二種

class Program : IComparer<FirstType>{    static void Main(string[] args)    {        FirstType f1 = new FirstType(3);        FirstType f2 = new FirstType(5);        FirstType f3 = new FirstType(2);        FirstType f4 = new FirstType(1);        List<FirstType> list = new List<FirstType>        {            f1,f2,f3,f4        };        list.Sort(new Program());        foreach (var item in list)        {            Console.WriteLine(item);        }    }    int IComparer<FirstType>.Compare(FirstType x, FirstType y)    {        return x.age.CompareTo(y.age);    }}

它調用的是Program的Compare方法

11、區別對待==和Equals

無論是== 還是Equals:

對於實值型別,如果類型的值相等,則返回True

對於參考型別,如果類型指向同一個對象,則返回True

且他們都可以被重載

對於string這樣一個特殊的引用類,微軟可能認為它的現實意義更傾向於一個實值型別,所以在FCL(Framework Class Library)中string的比較被重載為值比較,而不是針對引用本身

從設計上來說,很多參考型別會存在類似於string類型比較相近的情況,如人,他的社會安全號碼相同,則我們就認為是一個人,這個時候就需要重載Equals方法,

一般來說,對於參考型別,我們要定義值相等的特性,應該僅僅重寫Equals方法,同時讓==表示引用相等,這樣我們想比較哪個都是可以的

由於操作符“==”和“Equals”都可以被重載為“值相等”和“引用相等”,所以為了明確,FCL提供了object.ReferenceEquals(); 來比較兩個執行個體是否為同一個引用

12、重寫Equals時也要重寫GetHashCode

字典中判斷ContainsKey的時候使用的是key類型的HashCode,所以我們想都使用類型中的某個值來作為判斷條件,就需要重新GetHashCode,當然還有其他使用HashCode來作為判斷是否相等的,如果我們不重寫,可以會產生其他的效果

public override int GetHashCode(){    //這樣寫是為了減少HashCode重複的機率,至於為什麼這樣寫我也不清楚。。 記著就行    return (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName +            "#" + age).GetHashCode();}

重寫Equals方法的同時,也應該事先一個型別安全的介面IEquatable<T> ,所以重寫Equals的最終版本應該是

class FirstType : IEquatable<FirstType>{    public string name;    public int age;    public FirstType(int age)    {        name = "aa";        this.age = age;    }    public override bool Equals(object obj)    {        return age.Equals(((FirstType)obj).age);    }    public bool Equals(FirstType other)    {        return age.Equals(other.age);    }    public override int GetHashCode()    {        return (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName +                "#" + age).GetHashCode();    }}

13、為類型輸出格式化字串

class Person : IFormattable{    public override string ToString()    {        return "Default Hello";    }    public string ToString(string format, IFormatProvider formatProvider)    {        switch (format)        {            case "Chinese":                return "你好";            case "English":                return "Hello";        }        return "helo";    }}
static void Main(string[] args){    Person p1 = new Person();    Console.WriteLine(p1);    Console.WriteLine(p1.ToString("Chinese",null));    Console.WriteLine(p1.ToString("English", null));}

當繼承了IFormattable介面後,可以在ToString裡面穿參數來調用不同的ToString,上面的預設ToString就不會調用到了

具體還有一個IFormatProvider介面,我還沒研究

14、正確實現淺拷貝和深拷貝

無論是深拷貝還是淺拷貝,微軟都見識用類型繼承ICloneable介面的方式來明確告訴調用者:該類型可以被拷貝

//記得在類前添加[Serializable]的標誌[Serializable]class Person : ICloneable{    public string name;    public Child child;    public object Clone()    {        //淺拷貝        return this.MemberwiseClone();    }    /// <summary>    /// 深拷貝    /// 我也不清楚為什麼這樣寫    /// </summary>    /// <returns></returns>    public Person DeepClone()    {        using (Stream objectStream = new MemoryStream())        {            IFormatter formatter = new BinaryFormatter();            formatter.Serialize(objectStream, this);            objectStream.Seek(0, SeekOrigin.Begin);            return formatter.Deserialize(objectStream) as Person;        }    }}[Serializable]class Child{    public string name;    public Child(string name)    {        this.name = name;    }    public override string ToString()    {        return name;    }}

淺拷貝:

輸出的p1.child.name 是更改過的p2的child.name

深拷貝:

輸出的是原來的

深拷貝是對於參考型別來說,理論上string類型是參考型別,但是由於該參考型別的特殊性,Object.MemberwiseClone仍然為其建立了副本,也就是說在淺拷貝過程中,我們應該將字串看成是實值型別

15、使用dynamic來簡化反射實現

static void Main(string[] args){    //使用反射    Stopwatch watch = Stopwatch.StartNew();    Person p1 = new Person();    var add = typeof(Person).GetMethod("Add");    for (int i = 0; i < 1000000; i++)    {        add.Invoke(p1, new object[] { 1, 2 });    }    Console.WriteLine(watch.ElapsedTicks);    //使用dynamic    watch.Reset();    watch.Start();    dynamic d1 = new Person();    for (int i = 0; i < 1000000; i++)    {        d1.Add(1, 2);    }    Console.WriteLine(watch.ElapsedTicks);}

可以看出使用dynamic會比使用反射寫出來的代碼美觀且簡潔,而且多次啟動並執行效率也會更高,因為dynamic第一次運行後會緩衝起來

幾乎相差了10倍

但是反射如果次數較少效率會更高

這個是運行了100次的結果

但是很多時候效率不是必要的,始終推薦使用dynamic來簡化反射的實現

相關文章:

C#學習記錄:編寫高品質代碼改善整理建議1-3

C#學習記錄:編寫高品質代碼改善整理建議4-8

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.