2010-10-22 10 views
10

Tengo un proyecto con muchos cálculos que implican una gran cantidad de unidades del mundo real:El uso de unidades del mundo real en lugar de tipos

  • Distancia;
  • Temperatura;
  • Caudal;
  • ...

Este proyecto consiste en fórmulas de cálculo complicadas y numerosas.

Es por eso que se supone el uso de tipos personalizados como Temperatura, Distancia ... puede ser bueno para la legibilidad del código. Por ejemplo:

Temperature x = -55.3; 
Meter y = 3; 

o

var x = new Temperature(-55.3); 

Traté de hacer una clase de temperatura que utiliza un valor interno doble.

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); 
    } 
} 

Pero la clase es nulable. Esto significa que algo así como:

Temperature myTemp; 

es "correcto" y será nulo. No quiero esto. No quiero utilizar estructuras ya que son demasiado limitados:

  • No pueden usar intializers constructor ni campo de instancia sin parámetros como double _Value = double.Nan; para definir un valor por defecto (I varita por defecto subyacente doble valor para que sea NaN)
  • No pueden hereda de clases, sólo pueden implementar interfaces

ellos me pregunto si hay una manera de saber C#:

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

pero sé que C# no maneja unidades personalizadas.

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

así que me imagino que podría crear dos clases Celsius y Kelvin que hereda de la temperatura, y luego empecé a preguntarse si la idea realmente vale la pena, ya que implica una gran cantidad de codificación y pruebas.

Esa es la discusión me gustaría empezar:

estaría el uso de unidades del mundo real en mi código en lugar de tipos de .NET sería una buena cosa o no? ¿Alguien ya esta? ¿Cuáles son las trampas y las mejores prácticas? ¿O debería mantenerme alejado de esto y usar tipos .NET estándar?

+2

Sidenote: F # admite unidades de forma nativa – CodesInChaos

+7

¿Por qué crees que las estructuras son limitadas? Creo que las estructuras son exactamente lo que usaré aquí. Sus clases tendrán un único valor numérico e inmutable: caso de uso ideal para las estructuras. – NOtherDev

+0

Interresting! Desafortunadamente no puedo permitirme usar F # en mi proyecto. Pero definitivamente noto esto para el futuro – Larry

Respuesta

1

Una forma de lograr esto sería utilizar la composición del objeto básico (Temperature en su caso) con una clase TemperatureTraits que especializa el objeto básico. Por analogía a C++, la clase equivalente Stringbasic_string es en realidad una plantilla de clase (genérica en términos C#) que tiene parámetros de plantilla no solo para el elemento de cadena (char, char ancho) sino también una clase de rasgos que explica cómo se comporta la clase un tipo dado de elemento de cuerda (por ejemplo, char_traits).

En su caso, es posible definir un genérico como

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

y luego puesta en práctica habría dependerá no sólo de la clase medible, sino también en la clase de unidades. Lo útil que esto sería en la práctica dependería de qué parte de dicho objeto se pudiera convertir en genérico. ¿Qué operaciones son comunes en las combinaciones de Measurable y Units?

Hay un trabajo de investigación sobre los rasgos de C# here, si este enfoque parece interesante.

+0

Este es un documento * realmente * interesante. Desafortunadamente, no creo que pueda aplicarlo para este proyecto debido a las limitaciones de tiempo y la complejidad del cálculo en el que me tengo que enfocar. +1 de todos modos y enlace marcado como favorito. Gracias ! – Larry

+1

@controlbreak - ¿Has visto esta publicación relacionada? http://stackoverflow.com/questions/348853/units-of-measure-in-c-almost –

+0

Me encanta ese último enlace. ¡Aceptado! – Larry

0

Creo que puede ser bueno cuando desea agregar funcionalidad más específica a una temperatura (por ejemplo: IsFreezing()).

Para resolver el problema con Kelvin y Celsius: hacer una interfaz ITemperature y una clase base. En la clase base, puede implementar la interfaz y completar los detalles que son iguales para todas las clases.

0

Si utiliza una estructura, entonces esto puede no ser null

struct Temperature 
{ 
    double _Value; 
} 
0

no creo que vale la pena añadir tipos de unidades estáticas en C#. Debería sobrecargar tantos operadores (para todas las combinaciones de unidades, no solo para todas las unidades). Y construir en funciones como el trabajo en Math.Sqrt dobles normales, ...

Lo que usted podría intentar es el uso de tipos dinámicos:

class PhysicalUnit 
{ 
} 

struct PhysicalValue 
{ 
    readonly Value; 
    readonly PhysicalUnit; 
} 

Y luego cuando se compila en modo de depuración añadir comprueba si las unidades encajan . Y en la versión solo elimina el campo PhysicalUnit y todas las comprobaciones, y eres (casi) tan rápido como el código con dobles normales.

10

Por qué no probar una estructura que se parece a esto:

/// <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; } 
    } 
} 

A continuación, utilizarlo como, por ejemplo, esto:

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 para la muestra ** struct ** inmutable. –

+0

El problema con esto es que se necesita una cantidad enorme de clases y operadores aún más sobrecargados. Dado que en física * muchas * combinaciones de unidades son útiles. – CodesInChaos

+0

Pero esta es solo una clase para la idea de la temperatura. ¿Cómo lo resolverías con menos teniendo en cuenta las limitaciones que tenemos en el lenguaje? No veo que sea un problema. Además, la sobrecarga tendrá que suceder de todos modos para cada unidad. Este método los minimiza en comparación con tener más clases como se sugiere en la pregunta. –

0

me haría Temperature una clase abstracta que almacena la temperatura (en Kelvin!) En una propiedad de temperatura interna.

Una clase derivada Celcius traduciría internamente el valor de entrada a Kelvin. Tendría una propiedad Value (solo) que tradujo el valor interno nuevamente.

Compararlos (es uno más cálido que el otro) sería fácil.

Cuestiones relacionadas