Bonnes pratiques pour la surcharge des opérateurs
Conservez des opérateurs surchargés intuitifs.
Bonnes pratiques pour la surcharge des opérateurs est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.
Bonnes pratiques de surcharge des opérateurs
La surcharge des opérateurs est un outil puissant. Bien utilisée, elle rend les types valeur intuitifs ; mal utilisée, elle rend le code cryptique. Cette leçon présente les principes qui rendent les opérateurs surchargés prévisibles.
Ne surchargez que lorsque la signification est évidente
Ne surchargez un opérateur que lorsque sa signification est sans ambiguïté pour votre type. + sur un vecteur signifie clairement une addition composante par composante ; + sur un Order ne ferait que dérouter les lecteurs.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
// + means adding components: obvious and expected
public static Vector2 operator +(Vector2 a, Vector2 b)
=> new Vector2(a.X + b.X, a.Y + b.Y);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Vector2(1, 2) + new Vector2(3, 4));
}
}Préserver les attentes mathématiques
Faites en sorte que les opérateurs restent conformes à l'intuition : a + b devrait être égal à b + a lorsque les mathématiques sont commutatives, et + ne devrait pas soustraire secrètement. Ces surprises provoquent des bogues subtils.
using System;
public struct Money
{
public decimal Amount;
public Money(decimal a) { Amount = a; }
public static Money operator +(Money a, Money b) => new Money(a.Amount + b.Amount);
public override string ToString() => "$" + Amount;
}
public class Program
{
public static void Main()
{
var x = new Money(3);
var y = new Money(5);
Console.WriteLine((x + y).Amount == (y + x).Amount); // commutative
}
}Conserver la symétrie et les paires
Le langage associe certains opérateurs, mais vous devriez également préserver la symétrie logique : si vous ajoutez +, envisagez - ; si vous ajoutez <, fournissez également > et les variantes avec signe égal. Les ensembles d'opérateurs incomplets frustrent les utilisateurs.
using System;
public struct Length
{
public int Mm;
public Length(int mm) { Mm = mm; }
public static Length operator +(Length a, Length b) => new Length(a.Mm + b.Mm);
public static Length operator -(Length a, Length b) => new Length(a.Mm - b.Mm);
public override string ToString() => Mm + "mm";
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Length(50) + new Length(20));
Console.WriteLine(new Length(50) - new Length(20));
}
}Ne modifiez pas les opérandes
Les opérateurs devraient être purs : calculez et renvoyez une nouvelle valeur, sans modifier les opérandes. Modifier un opérande dans + rompt toutes les attentes du lecteur.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public static Vector2 operator +(Vector2 a, Vector2 b)
=> new Vector2(a.X + b.X, a.Y + b.Y); // returns new, mutates nothing
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var a = new Vector2(1, 1);
var unused = a + new Vector2(9, 9);
Console.WriteLine("a is still " + a);
}
}Garder == cohérent avec Equals
Une bonne pratique récurrente : chaque fois que vous surchargez ==, redéfinissez Equals et GetHashCode afin que toutes les formes d'égalité concordent. Une incohérence à ce niveau est l'un des bogues d'opérateur les plus courants.
using System;
public struct Point
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public override bool Equals(object obj) => obj is Point p && p.X == X && p.Y == Y;
public override int GetHashCode() => HashCode.Combine(X, Y);
public static bool operator ==(Point a, Point b) => a.Equals(b);
public static bool operator !=(Point a, Point b) => !a.Equals(b);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Point(1, 1) == new Point(1, 1));
}
}Fournir des alternatives nommées
Certains langages et outils d'analyse ne peuvent pas utiliser les opérateurs. Proposer une méthode nommée telle que Add en plus de + améliore l'interopérabilité et la découverte.
using System;
public struct Vector2
{
public int X, Y;
public Vector2(int x, int y) { X = x; Y = y; }
public Vector2 Add(Vector2 other) => new Vector2(X + other.X, Y + other.Y);
public static Vector2 operator +(Vector2 a, Vector2 b) => a.Add(b);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
var v = new Vector2(1, 2);
Console.WriteLine(v.Add(new Vector2(3, 4)));
Console.WriteLine(v + new Vector2(3, 4));
}
}Privilégier les opérateurs pour les types proches des valeurs
Les opérateurs semblent naturels sur les types immuables proches des valeurs (structures ou classes similaires aux enregistrements). Pour les types mutables dont l'identité est importante, les méthodes nommées expriment généralement mieux l'intention.
using System;
public readonly struct Rational
{
public readonly int Num, Den;
public Rational(int n, int d) { Num = n; Den = d; }
public static Rational operator *(Rational a, Rational b)
=> new Rational(a.Num * b.Num, a.Den * b.Den);
public override string ToString() => Num + "/" + Den;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Rational(1, 2) * new Rational(2, 3));
}
}Documenter les cas limites
Précisez explicitement comment les opérateurs gèrent les valeurs particulières : division par zéro, opérandes nuls pour les classes ou dépassement de capacité. Un comportement prévisible évite de prendre les appelants au dépourvu.
using System;
public struct SafeDiv
{
public int Value;
public SafeDiv(int v) { Value = v; }
// Documented behavior: dividing by zero yields zero
public static SafeDiv operator /(SafeDiv a, SafeDiv b)
=> new SafeDiv(b.Value == 0 ? 0 : a.Value / b.Value);
public override string ToString() => Value.ToString();
}
public class Program
{
public static void Main()
{
Console.WriteLine(new SafeDiv(10) / new SafeDiv(0));
Console.WriteLine(new SafeDiv(10) / new SafeDiv(2));
}
}Un ensemble d'opérateurs rigoureux
Un type numérique abouti associe quelques opérateurs intuitifs, une égalité cohérente et l'immuabilité. Le résultat se comporte comme un nombre intégré et est agréable à utiliser.
using System;
public readonly struct Vec
{
public readonly double X, Y;
public Vec(double x, double y) { X = x; Y = y; }
public static Vec operator +(Vec a, Vec b) => new Vec(a.X + b.X, a.Y + b.Y);
public static Vec operator -(Vec a, Vec b) => new Vec(a.X - b.X, a.Y - b.Y);
public static Vec operator *(Vec a, double k) => new Vec(a.X * k, a.Y * k);
public override string ToString() => "(" + X + ", " + Y + ")";
}
public class Program
{
public static void Main()
{
Console.WriteLine((new Vec(1, 2) + new Vec(3, 4)) * 2);
}
}Essayez vous-même
Mettez ces pratiques en application : un type valeur immuable, des opérateurs intuitifs, une alternative nommée et une égalité cohérente.
using System;
public readonly struct Meters : IEquatable<Meters>
{
public readonly double Value;
public Meters(double v) { Value = v; }
public Meters Add(Meters other) => new Meters(Value + other.Value);
public static Meters operator +(Meters a, Meters b) => a.Add(b);
public bool Equals(Meters other) => Value == other.Value;
public override bool Equals(object obj) => obj is Meters m && Equals(m);
public override int GetHashCode() => Value.GetHashCode();
public static bool operator ==(Meters a, Meters b) => a.Equals(b);
public static bool operator !=(Meters a, Meters b) => !a.Equals(b);
public override string ToString() => Value + "m";
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Meters(3) + new Meters(4));
Console.WriteLine(new Meters(7) == new Meters(7));
}
}Vérification rapide
Appliquez les bonnes pratiques de surcharge des opérateurs.
Récapitulatif
Une bonne surcharge des opérateurs est rigoureuse et prévisible.
- Ne surchargez que lorsque la signification est évidente.
- Préservez les attentes mathématiques et la symétrie.
- Restez purs : renvoyez de nouvelles valeurs et ne modifiez jamais les opérandes.
- Gardez
==cohérent avecEquals/GetHashCode. - Proposez des alternatives nommées et privilégiez les types proches des valeurs.
Questions Fréquemment Posées
La leçon « Bonnes pratiques pour la surcharge des opérateurs » est-elle gratuite ?
Oui — le texte complet de « Bonnes pratiques pour la surcharge des opérateurs » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Bonnes pratiques pour la surcharge des opérateurs » ?
Conservez des opérateurs surchargés intuitifs. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C# Academy ?
Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Bonnes pratiques pour la surcharge des opérateurs » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?
Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Surcharge des opérateurs arithmétiques
- Surcharge des opérateurs de comparaison
- Conversions définies par l’utilisateur
- Bonnes pratiques pour la surcharge des opérateurs