Surcharges d'opérateurs

Remarque

Ce contenu est réimprimé avec l’autorisation de Pearson Education, Inc. à partir des Instructions de conception d’une infrastructure : conventions, idiomes et modèles des bibliothèques réutilisables .NET, 2ème édition. Cette édition a été publiée en 2008, et le livre a été entièrement révisé dans la troisième édition. Certaines informations de cette page peuvent être obsolètes.

Les surcharges d’opérateur permettent aux types de framework d’apparaître comme s’il s’agissait de primitives de langage intégrées.

Bien qu’autorisées et utiles dans certaines situations, les surcharges d’opérateur doivent être utilisées avec prudence. Il existe de nombreux cas dans lesquels la surcharge d’opérateur a été utilisée, par exemple lorsque les concepteurs de framework ont commencé à utiliser des opérateurs pour les opérations qui devraient être des méthodes simples. Les instructions suivantes devraient vous aider à décider quand et comment utiliser la surcharge d’opérateur.

❌ ÉVITEZ de définir des surcharges d’opérateur, sauf dans les types qui doivent ressembler à des types primitifs (intégrés).

✔️ ENVISAGEZ de définir des surcharges d’opérateur dans un type qui doit ressembler à un type primitif.

Par exemple, System.String a operator== et operator!= définis.

✔️ DÉFINISSEZ les surcharges d’opérateur dans des structs qui représentent des nombres (comme System.Decimal).

❌ N’utilisez PAS de noms exotiques lors de la définition des surcharges d’opérateur.

La surcharge de l’opérateur est utile dans les cas où le résultat de l’opération est immédiatement évident. Par exemple, il est judicieux de pouvoir soustraire un DateTime d’un autre DateTime et obtenir un TimeSpan. Toutefois, il n’est pas approprié d’utiliser l’opérateur d’union logique pour unir deux requêtes de base de données, ou d’utiliser l’opérateur de décalage pour écrire dans un flux.

❌ NE fournissez PAS de surcharges d’opérateur, sauf si au moins l’un des opérandes est du type qui définit la surcharge.

✔️ EFFECTUEZ vos surcharges d’opérateur de manière symétrique.

Par exemple, si vous surchargez operator==, vous devez également surcharger operator!=. De même, si vous surchargez operator<, vous devez également surcharger operator>, et ainsi de suite.

✔️ ENVISAGEZ de fournir des méthodes avec des noms conviviaux qui correspondent à chaque opérateur surchargé.

De nombreux langages ne prennent pas en charge la surcharge des opérateurs. Pour cette raison, il est recommandé que les types qui surchargent des opérateurs incluent une méthode secondaire avec un nom propre au domaine approprié qui fournit des fonctionnalités équivalentes.

Le tableau suivant contient une liste d’opérateurs et les noms de méthode conviviaux correspondants.

Symbole de l’opérateur C# Nom des métadonnées Nom convivial
N/A op_Implicit To<TypeName>/From<TypeName>
N/A op_Explicit To<TypeName>/From<TypeName>
+ (binary) op_Addition Add
- (binary) op_Subtraction Subtract
* (binary) op_Multiply Multiply
/ op_Division Divide
% op_Modulus Mod or Remainder
^ op_ExclusiveOr Xor
& (binary) op_BitwiseAnd BitwiseAnd
| op_BitwiseOr BitwiseOr
&& op_LogicalAnd And
|| op_LogicalOr Or
= op_Assign Assign
<< op_LeftShift LeftShift
>> op_RightShift RightShift
N/A op_SignedRightShift SignedRightShift
N/A op_UnsignedRightShift UnsignedRightShift
== op_Equality Equals
!= op_Inequality Equals
> op_GreaterThan CompareTo
< op_LessThan CompareTo
>= op_GreaterThanOrEqual CompareTo
<= op_LessThanOrEqual CompareTo
*= op_MultiplicationAssignment Multiply
-= op_SubtractionAssignment Subtract
^= op_ExclusiveOrAssignment Xor
<<= op_LeftShiftAssignment LeftShift
%= op_ModulusAssignment Mod
+= op_AdditionAssignment Add
&= op_BitwiseAndAssignment BitwiseAnd
|= op_BitwiseOrAssignment BitwiseOr
, op_Comma Comma
/= op_DivisionAssignment Divide
-- op_Decrement Decrement
++ op_Increment Increment
- (unary) op_UnaryNegation Negate
+ (unary) op_UnaryPlus Plus
~ op_OnesComplement OnesComplement

Opérateur de surcharge ==

La surcharge de operator == est assez compliquée. La sémantique de l’opérateur doit être compatible avec plusieurs autres membres, comme Object.Equals.

Opérateurs de conversion

Les opérateurs de conversion sont des opérateurs unaires qui autorisent la conversion d’un type à un autre. Les opérateurs doivent être définis en tant que membres statiques sur l’opérande ou le type de retour. Il existe deux types d’opérateurs de conversion : implicite et explicite.

❌ NE fournissez PAS d’opérateur de conversion si une telle conversion n’est pas clairement attendue par les utilisateurs finaux.

❌ NE définissez PAS les opérateurs de conversion en dehors du domaine d’un type.

Par exemple, Int32, Double et Decimal sont tous des types numériques, alors que DateTime ne l’est pas. Par conséquent, il ne doit pas y avoir d’opérateur de conversion pour convertir un Double(long) en DateTime. Un constructeur est préféré dans ce cas.

❌ NE fournissez PAS d’opérateur de conversion implicite si la conversion comporte un risque de perte.

Par exemple, il ne doit pas y avoir de conversion implicite de Double en Int32, car Double a une plage plus large que Int32. Un opérateur de conversion explicite peut être fourni même si la conversion comporte un risque de perte.

❌ NE levez PAS d’exceptions des casts implicites.

Il est très difficile pour les utilisateurs finaux de comprendre ce qui se passe, car ils peuvent ne pas être conscients qu’une conversion est en cours.

✔️ LEVEZ System.InvalidCastException si un appel à un opérateur cast entraîne une conversion avec perte et que le contrat de l’opérateur n’autorise pas les conversions avec perte.

Portions © 2005, 2009 Microsoft Corporation. Tous droits réservés.

Réimprimé avec l’autorisation de Pearson Education, Inc. et extrait de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition par Krzysztof Cwalina et Brad Abrams, publié le 22 octobre 2008 par Addison-Wesley Professional dans le cadre de la série sur le développement Microsoft Windows.

Voir aussi