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
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); } }
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
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
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< T> 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(); } }
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)); }
<. 🎜>
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; } }
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); }
La différence est presque 10 fois
Mais si le nombre de réflexions est plus petit, l'efficacité sera plus élevéeC'est le résultat de 100 exécutions
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!