Maison  >  Article  >  développement back-end  >  Dossier d'apprentissage C# : Suggestions pour écrire du code de haute qualité et l'améliorer 9-15

Dossier d'apprentissage C# : Suggestions pour écrire du code de haute qualité et l'améliorer 9-15

php是最好的语言
php是最好的语言original
2018-08-06 14:57:001471parcourir

9. Habituez-vous à la surcharge des opérateurs

Lorsque vous créez vos propres types, vous devez toujours vous demander si vous pouvez utiliser la surcharge des opérateurs

10. Lors de la création d'un objet, vous devez déterminer s'il convient d'implémenter un comparateur

Si vous devez trier, il existe deux implémentations de comparateur

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);
    }
}

Dossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15

ou le deuxième

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);
    }
}

Il appelle la méthode Compare du programme

11 Traiter == et Equals différemment

Que ce soit == ou Equals. :

Pour les types valeur, si les valeurs des types sont égales, il renvoie True

Pour les types référence, si les types pointent vers le même objet, il renvoie True

et ils peuvent tous être surchargés

Pour une classe de référence spéciale comme une chaîne, Microsoft peut penser que sa signification pratique est plus encline à un type valeur, donc en FCL (Fcadre Class L ibrary) la comparaison de chaînes est surchargée en tant que comparaison de valeurs, pas pour la référence elle-même

En termes de conception, de nombreux types de référence seront similaires aux types de chaînes , comme des personnes, d'autres Si leurs numéros d'identification sont les mêmes, nous les considérons comme la même personne. À ce stade, nous devons surcharger la méthode Equals

De manière générale, pour les types de référence, nous avons besoin. pour définir la caractéristique des valeurs égales, et nous devons uniquement remplacer la méthode Equals. et laisser == représenter l'égalité de référence, afin que nous puissions comparer celle que nous voulons

Puisque les deux opérateurs "==" et "Equals" peut être surchargé en tant que « égalité de valeur » et « égalité de référence » », donc par souci de clarté, FCL fournit object.ReferenceEquals(); pour comparer si deux instances sont la même référence

12. , vous devez également réécrire GetHashCode

dans le dictionnaire Lors du jugement de ContainsKey, le HashCode du type de clé est utilisé, donc si nous voulons utiliser une certaine valeur dans le type comme condition de jugement, nous devons à nouveau getHashCode . Bien sûr, il existe d'autres méthodes qui utilisent HashCode pour juger si elles sont égales. Si nous ne répétons pas, l'écriture peut produire d'autres effets

public override int GetHashCode()
{
    //这样写是为了减少HashCode重复的概率,至于为什么这样写我也不清楚。。 记着就行
    return (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName +
            "#" + age).GetHashCode();
}

Lors de la réécriture de la méthode Equals, une interface de type sécurisé IEquatable doit également être fourni à l'avance, donc la version finale de la réécriture de Equals doit être

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. Chaîne formatée en sortie pour le type

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));
}

Dossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15<.>

Après avoir hérité de l'interface IFormattable, vous pouvez l'appeler avec des paramètres dans ToString Différents ToString, le ToString par défaut ci-dessus ne sera pas appelé

Il existe également une interface IFormatProvider, que je n'ai pas encore étudiée

14. Implémenter correctement la copie superficielle et la copie profonde

Qu'il s'agisse d'une copie profonde ou d'une copie superficielle, Microsoft utilise l'interface ICloneable d'héritage de type pour clairement dites à l'appelant : ce type peut être copié

//记得在类前添加[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;
    }
}
Copie superficielle :

Dossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15

La sortie p1.child.name est le nom de l'enfant modifié de p2

Copie approfondie :

Dossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15

La sortie est l'original

La copie approfondie est destinée aux types de référence. En théorie, le type de chaîne est. un type référence, mais en raison de la particularité de ce type référence, Object.MemberwiseClone est toujours créé pour sa copie, c'est-à-dire que pendant le processus de copie superficielle, nous devons considérer la chaîne comme un type valeur

15. Utilisez Dynamic pour simplifier la mise en œuvre de la réflexion

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);
}
On peut voir que l'utilisation de Dynamic sera plus belle et plus concise que le code écrit en utilisant la réflexion, et l'efficacité des exécutions multiples sera plus élevée, car la dynamique sera mise en cache après la première exécution

La différence est presque 10 foisDossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15

Mais si le nombre de réflexions est plus petit, l'efficacité sera plus élevée

C'est le résultat de 100 exécutions Dossier dapprentissage C# : Suggestions pour écrire du code de haute qualité et laméliorer 9-15

Mais dans de nombreux cas l'efficacité n'est pas nécessaire, il est toujours recommandé d'utiliser la dynamique pour simplifier la mise en œuvre de la réflexion

Articles associés :

Record d'apprentissage C# : rédaction de suggestions d'amélioration de code de haute qualité 1-3

Record d'apprentissage C# : rédaction de suggestions d'amélioration de code de haute qualité 4-8

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn