2012-01-19 19 views
9

Supponiamo che io ho una struct con un solo campo:Devo definire ogni singolo operatore?

public struct Angle 
{ 
    public static readonly double RadiansPerDegree = Math.PI/180; 

    private readonly double _degrees; 

    public Angle(double degrees) 
    { 
     _degrees = degrees; 
    } 

    public double Degrees 
    { 
     get { return _degrees; } 
    } 

    public double Radians 
    { 
     get { return _degrees * RadiansPerDegree; } 
    } 

    public static Angle FromDegrees(double value) 
    { 
     return new Angle(value); 
    } 

    public static Angle FromRadians(double value) 
    { 
     return new Angle(value/RadiansPerDegree); 
    } 
} 

Questa grande opera, fino a che non voglio fare cose come questa:

var alpha = Angle.FromDegrees(90); 
var beta = Angle.FromDegrees(100); 
var inequality = alpha > beta; 
var sum = alpha + beta; 
var negation = -alpha; 
//etc. 

Così, ho implementato IEquatable<in T> e IComparable<in T>, ma che ancora non ha abilitato alcun operatore (nemmeno ==, <, >=, ecc.).

Quindi, ho iniziato a fornire sovraccarichi dell'operatore.

Ad esempio:

public static Angle operator +(Angle a, Angle b) 
{ 
    return new Angle(a._degrees + b._degrees); 
} 

public static Angle operator -(Angle a) 
{ 
    return new Angle(-a._degrees); 
} 

public static bool operator >(Angle a, Angle b) 
{ 
    return a._degrees > b._degrees; 
} 

Questo ha funzionato, però, quando ho guardato tutti gli operatori che, concettualmente, potrebbe sovraccarico (+, -, !, ~, ++, --, true, false, +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=), ho iniziato a sentire come ci deve essere un modo migliore. Dopo tutto, la struttura contiene solo un campo e quel campo è un tipo di valore.

C'è un modo per abilitare tutti gli operatori di double in un solo colpo? O devo davvero digitare ogni operatore che potrei voler supportare a mano?

(Anche se ho avuto due o tre campi, mi piace ancora di essere in grado di aggiungere gli operatori in un unico lotto ...)

+3

Probabilmente si potrebbe aggiungere al cast impliciti (e possibilmente da) il tipo 'double' per farlo. Tuttavia, qualcosa nella mia testa mi dice che potrebbe non essere una buona idea e potrebbe portare ad ambiguità. –

+1

Se si sta davvero facendo questo solo per la conversione in gradi e radianti, perché non avere solo una classe MathHelper statica che implementa quelle funzionalità e basta usare double invece di creare una classe che inventa un'altra classe con un nome diverso? –

+0

@Jeff Mercado, penso che un cast implicito potrebbe essere proprio quello che sto cercando, in realtà. Prenderesti in considerazione la possibilità di convertire il tuo commento in una risposta? Inoltre, se c'è davvero un rovescio della medaglia, sarei davvero grato se potessi ampliarlo un po '. Grazie. – devuxer

risposta

12

Il punto di operatori coppia è quello di definire come aggiungere manipolare oggetti di un tipo personalizzato che usano quegli operatori, quindi se il tuo secondo campo fosse un array di stringhe, come ti aspetteresti che l'operatore ++ fosse implementato automaticamente? Non c'è una risposta sensata, soprattutto perché non conosciamo il contesto dell'oggetto o il suo utilizzo, quindi la risposta è sì, è necessario sovraccaricare gli operatori da soli.

Per la cronaca, se in realtà hai solo bisogno di un campo, ed è solo un doppio, allora non usare una struct in primo luogo a meno che non sia necessario sovraccaricare gli operatori per eseguire qualche altra azione rispetto a quella di default - è un chiaro caso di over-engineering!

+0

L'esempio 'Angle' è una semplificazione, ma il mio obiettivo è quello di rendere molto chiaro quali sono le unità e incapsulare la conversione necessaria tra le unità in un singolo tipo. Quindi, se ho un 'Angolo', non c'è alcuna ambiguità riguardo le unità, semplicemente afferro qualsiasi cosa di cui ho bisogno. Quello che stavo ottenendo con la mia domanda era che, vorrei che ci fosse un modo per dire al compilatore che voglio che la struttura si comporti come se fosse il campo sottostante per tutte le operazioni. Il suggerimento di @Jeff Mercado di utilizzare i cast impliciti * sembra * per realizzare ciò, ma sembra preoccupato che possano esserci conseguenze non intenzionali. – devuxer

+0

Non appena i tipi sono qualcosa di più complicato di quelli primitivi, puoi vedere come un sistema non sarebbe in grado di generare operazioni significative per i dati in questione. Almeno sai cosa stai facendo! Suggerirei magari di creare una macro in un IDE come Vim per generare tutti gli operatori per le tue strutture se è qualcosa che farai più di una volta. –

+0

Penso che in tutti i miei casi prevedo per questo particolare progetto, posso implicitamente convertire l'intero tipo in un singolo tipo di valore nativo allo scopo di eseguire operazioni, ma se mi imbatto in qualcosa di più complesso, l'idea macro per generare il i sovraccarichi dell'operatore suonano bene. – devuxer

0

Sì, è necessario definire ogni operatore che si desidera utilizzare. Il compilatore non ha modo di sapere cosa vuoi fare ogni operatore, a parte gli operatori che sono negativi l'uno dell'altro (e anche quelli potrebbero non essere ovvi, e se volessi imitare il comportamento SQL SQL standard dove sia == e != restituire false rispetto a null?).

0

Per la maggior parte dei casi sono d'accordo con LaceySnr: non funziona davvero per gli operatori che restituiscono il nuovo oggetto (ad es. +, * Ect.). Per i comparatori potrebbe funzionare (dato che potrebbe esserci un'annotazione che dice "usa il valore di ritorno di questo metodo come sostituto di questo oggetto se usato in tutte le operazioni di confronto"), ma non conosco nulla di simile.

Non sono sicuro quali siano le limitazioni delle annotazioni in C#, ma potrebbe essere possibile crearne uno che faccia ciò (per gli operatori che restituiscono bool), ma a meno che non steste pianificando di usarlo molto dubito ne varrà la pena.

Detto questo, se si dovesse avere un oggetto che richiedesse esattamente un argomento nel costruttore e quell'argomento fosse il valore di ritorno del metodo, dovrebbe essere possibile farlo anche per quello.

Naturalmente per fare tutto questo richiederà un po 'abbastanza estremo di classe-ritocchi, che io non sono davvero in una situazione di dare consigli su ...

Problemi correlati