2010-10-22 12 views
10

Ho un progetto con molti calcoli che coinvolge un sacco di unità del mondo reale:utilizzo di unità del mondo reale, invece di tipi

  • Distanza;
  • Temperatura;
  • Portata;
  • ...

Il progetto prevede formule di calcolo complesse e numerose.

Ecco perché ho supposto l'uso di tipi personalizzati come Temperatura, Distanza ... può essere buono per la leggibilità del codice. Ad esempio:

Temperature x = -55.3; 
Meter y = 3; 

o

var x = new Temperature(-55.3); 

ho cercato di fare una classe di temperatura che utilizza un valore doppio interna.

public class Temperature 
{ 
    double _Value = double.NaN; 

    public Temperature() { } 

    public Temperature(double v) { 
     _Value = v; 
    } 

    public static implicit operator Temperature(double v) { 
     return new Temperature(v); 
    } 
} 

Ma la classe è annullabile. Ciò significa che qualcosa del tipo:

Temperature myTemp; 

è "corretto" e sarà nullo. Non lo voglio Non voglio usare le strutture perché sono troppo limitati:

  • Essi non possono utilizzare senza parametri costruttore né campo di istanza intializers come double _Value = double.Nan; per definire un valore di default (I bacchetta di default sottostanti valore doppio per essere NaN)
  • Non possono eredita dalle classi, ma solo in grado di implementare interfacce

loro mi chiedo se ci sia un modo per dire C#:

Temperature myTemp = 23K; // C# does not implement anything to make K unit... 

ma so che C# non gestisce nessuna unità personalizzata.

Temperature myTemp = new Kelvin(23); // This might work 

quindi immagino che potrei creare due classi Celsius e Kelvin che eredita dalla temperatura, e poi ho iniziato a chiedermi se l'idea davvero la pena, perché si tratta di un sacco di codifica e test.

Questa è la discussione vorrei iniziare:

Sarebbe l'uso di unità del mondo reale nel mio codice, invece di tipi .NET sarebbe una cosa buona o no? Qualcuno lo ha già fatto? Quali sono le insidie ​​e le migliori pratiche? O dovrei stare lontano da questo e usare i tipi standard di .NET?

+2

Sidenote: F # supporta le unità in modo nativo – CodesInChaos

+7

Perché pensi che le strutture siano limitate? Penso che le strutture siano esattamente ciò che userò qui. Le tue lezioni porteranno solo un valore numerico e immutabile - caso d'uso ideale per le strutture. – NOtherDev

+0

Interruzione! Purtroppo non posso permettermi di usare F # nel mio progetto. Ma sicuramente lo ricordo per il futuro – Larry

risposta

1

Un modo per ottenere ciò sarebbe utilizzare la composizione dell'oggetto di base (Temperature nel tuo caso) con una classe TemperatureTraits che specializza l'oggetto di base. Per analogia con C++, la classe equivalente Stringbasic_string è in realtà un modello di classe (generico in termini C#) con parametri del modello non solo per l'elemento stringa (char, wide char) ma anche una classe di caratteri che elabora il comportamento della classe per un determinato tipo di elemento stringa (ad es. char_traits).

Nel tuo caso, si potrebbe definire un generico come

public class MeasurableWithUnits<class M MEASURABLE, class U UNITS>

e quindi implementazione dipenderebbe non solo sulla classe misurabile, ma anche sulla classe di unità. Quanto sarebbe utile in pratica dipenderebbe dalla quantità di tale oggetto che potrebbe essere reso veramente generico - quali operazioni sono comuni tra le combinazioni di Measurable e Units?

C'è un documento di ricerca sui tratti C# here, se questo approccio sembra interessante.

+0

Questo è un documento * veramente * interessante. Sfortunatamente, non penso che potrei applicarlo a questo progetto a causa dei limiti di tempo e della complessità del calcolo su cui devo concentrarmi. +1 in ogni caso e link segnalibro. Grazie ! – Larry

+1

@controlbreak - hai visto questo post correlato? http://stackoverflow.com/questions/348853/units-of-measure-in-c-almost –

+0

Amo questo ultimo link. Accettato! – Larry

0

Penso che possa essere utile quando si desidera aggiungere una funzionalità più specifica a una temperatura (ad esempio: IsFreezing()).

Per risolvere il problema con Kelvin e Celsius: creare un'interfaccia ITemperature e una baseclass. Nella classe di base è possibile implementare l'interfaccia e inserire i dettagli uguali per tutte le classi.

0

Se si utilizza una struttura, allora questo non può essere null

struct Temperature 
{ 
    double _Value; 
} 
0

non credo che valga la pena di aggiungere tipi statici per le unità in C#. Dovresti sovraccaricare così tanti operatori (per tutte le combinazioni di unità, non solo per tutte le unità). E costruire in funzioni come il lavoro Math.Sqrt su doppie normali, ...

Che cosa si potrebbe provare sta utilizzando i tipi dinamici:

class PhysicalUnit 
{ 
} 

struct PhysicalValue 
{ 
    readonly Value; 
    readonly PhysicalUnit; 
} 

E poi durante la compilazione in modalità debug aggiungere controlla se le unità combaciano . E in rilascio basta rimuovere il campo PhysicalUnit e tutti i controlli, e sei (quasi) veloce come il codice usando i normali doppi.

10

Perché non provare uno struct che assomiglia a questo:

/// <summary> 
/// Temperature class that uses a base unit of Celsius 
/// </summary> 
public struct Temp 
{ 
    public static Temp FromCelsius(double value) 
    { 
     return new Temp(value); 
    } 

    public static Temp FromFahrenheit(double value) 
    { 
     return new Temp((value - 32) * 5/9); 
    } 

    public static Temp FromKelvin(double value) 
    { 
     return new Temp(value - 273.15); 
    } 

    public static Temp operator +(Temp left, Temp right) 
    { 
     return Temp.FromCelsius(left.Celsius + right.Celsius); 
    } 

    private double _value; 

    private Temp(double value) 
    { 
     _value = value; 
    } 

    public double Kelvin 
    { 
     get { return _value + 273.15; } 
    } 

    public double Celsius 
    { 
     get { return _value; } 
    } 

    public double Fahrenheit 
    { 
     get { return _value/5 * 9 + 32; } 
    } 
} 

Poi usarlo come, ad esempio, questo:

static void Main(string[] args) 
    { 
     var c = Temp.FromCelsius(30); 
     var f = Temp.FromFahrenheit(20); 
     var k = Temp.FromKelvin(20); 

     var total = c + f + k; 
     Console.WriteLine("Total temp is {0}F", total.Fahrenheit); 
    } 
+1

+1 per il ** esempio di struttura ** immutabile. –

+0

Il problema con questo è che è necessario un numero enorme di classi e operatori ancora più sovraccarichi. Dato che in fisica * molte * combinazioni di unità sono utili. – CodesInChaos

+0

Ma questa è solo una classe per l'idea della temperatura. Come lo risolveresti con meno dati i vincoli che abbiamo nella lingua? Non vedo che sia un problema. Inoltre, il sovraccarico dovrà verificarsi comunque per ciascuna unità. Questo metodo li minimizza rispetto ad avere più classi come suggerito nella domanda. –

0

mi farebbe Temperature una classe astratta che memorizza la temperatura (in Kelvin!) In una proprietà InternalTemperature.

Una classe derivata Celcius tradurrebbe il valore di input internaly in Kelvin. Avrebbe una proprietà Value (di sola lettura) che ha tradotto il valore interno.

Confrontarli (è uno più caldo dell'altro) sarebbe quindi facile.

Problemi correlati