Overload dell'operatore

Nota

Questo contenuto viene ristampato con l'autorizzazione di Pearson Education, Inc. da Framework Design Guidelines: Conventions, Idioms and Patterns for Reusable .NET Libraries, 2nd Edition. Tale edizione è stata pubblicata nel 2008 e il libro è stato completamente rivisto nella terza edizione. Alcune informazioni in questa pagina potrebbero non essere aggiornate.

Gli overload degli operatori consentono la visualizzazione dei tipi di framework come se fossero dei primitive del linguaggio predefiniti.

Anche se consentito e utile in alcune situazioni, gli overload degli operatori devono essere usati con cautela. Esistono molti casi in cui l'overload degli operatori è stato abusato, ad esempio quando i progettisti di framework hanno iniziato a usare gli operatori per le operazioni che devono essere metodi semplici. Le linee guida seguenti consentono di decidere quando e come usare l'overload degli operatori.

❌ EVITARE di definire gli overload degli operatori, ad eccezione dei tipi che devono essere simili ai tipi primitivi (predefiniti).

✔️ CONSIDERARE la definizione di overload degli operatori in un tipo che deve essere simile a un tipo primitivo.

Ad esempio, System.String ha operator== e operator!= definiti.

✔️ DEFINIRE gli overload degli operatori in struct che rappresentano dei numeri, ad esempio System.Decimal.

❌ NON bisogna essere gentili quando si definiscono gli overload degli operatori.

L'overload degli operatori è utile nei casi in cui è immediatamente ovvio quale sarà il risultato dell'operazione. Ad esempio, è opportuno essere in grado di sottrarre un oggetto DateTime da un altro oggetto DateTime e ottenere un oggetto TimeSpan. Non è tuttavia opportuno usare l'operatore di unione logica per unire due query di database o usare l'operatore shift per scrivere in un flusso.

❌ NON fornire overload degli operatori, a meno che almeno uno degli operandi non sia del tipo che definisce l'overload.

✔️ ESEGUIRE l’overload degli operatori in modo simmetrico.

Ad esempio, se si esegue l'overload di operator==, è necessario eseguire anche l'overload di operator!=. Analogamente, se si esegue l'overload di operator<, è necessario eseguire anche l'overload di operator>, e così via.

✔️ VALUTARE la possibilità di fornire metodi con nomi descrittivi che corrispondono a ogni operatore di overload.

Molti linguaggi non supportano l'overload degli operatori. Per questo motivo, è consigliabile che i tipi che eseguono l’overload degli operatori includano un metodo secondario con un nome specifico del dominio appropriato che fornisce funzionalità equivalenti.

La tabella seguente contiene un elenco di operatori e i nomi dei metodi descrittivi corrispondenti.

Simbolo dell'operatore C# Nome dei metadati Nome descrittivo
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

Overload degli operatori ==

L'overload di operator == è piuttosto complicato. La semantica dell'operatore deve essere compatibile con diversi altri membri, ad esempio Object.Equals.

Operatori di conversione

Gli operatori di conversione sono operatori unari che consentono la conversione da un tipo a un altro. Gli operatori devono essere definiti come membri statici nell'operando o nel tipo restituito. Esistono due tipi di operatori di conversione: impliciti ed espliciti.

❌ NON fornire un operatore di conversione se tale conversione non è chiaramente prevista dagli utenti finali.

❌ NON definire operatori di conversione all'esterno del dominio di un tipo.

Ad esempio, Int32, Double e Decimal sono tutti tipi numerici, mentre DateTime non lo è. Pertanto, non deve essere presente alcun operatore di conversione per convertire un oggetto Double(long) in un oggetto DateTime. In questo caso è preferibile un costruttore.

❌ NON fornire un operatore di conversione implicito se la conversione è potenzialmente in perdita.

Ad esempio, non deve essere presente una conversione implicita da Double a Int32 perché Double ha un intervallo più ampio di Int32. È possibile specificare un operatore di conversione esplicito anche se la conversione è potenzialmente in perdita.

❌ NON generare eccezioni dai cast impliciti.

È molto difficile per gli utenti finali capire cosa sta accadendo, perché potrebbero non essere consapevoli che si sta verificando una conversione.

✔️ GENERARE System.InvalidCastException se una chiamata a un operatore cast comporta una conversione in perdita e il contratto dell'operatore non consente conversioni in perdita.

Parti protette da copyright © 2005, 2009 Microsoft Corporation. Tutti i diritti sono riservati.

Ristampato con l'autorizzazione di Pearson Education, Inc. da Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2a edizione di Krzysztof Cwalina and Brad Abrams, pubblicato il 22 ottobre 2008 da Addison-Wesley Professional nella collana Microsoft Windows Development Series.

Vedi anche