Pregunta

Tengo un espacio de nombres de estructuras que representan diversas unidades de medida (metros, pies, pulgadas, etc.) ... anout 12 en total, cortesía generada de plantillas T4 :).

Cada struct lleva operadores conversión implícita para apoyar fundición el valor a cualquier otra medición de tipo de valor, por lo que el siguiente sytax es legal:

var oneThousandMeters = new Meters(1000);    
Kilometers aKilo = oneThousandMeters ;     // implicit cast OK. Value = 1 Km

Para añadir a la alegría, hay un cajón de sastre clase llamada Distancia que puede contener cualquier unidad de medida, y también se pueden emitir de forma implícita hacia y desde la medición y el valor ...

var magnum = new Distance(12, DistanceUnits.Inches); 
Feet wifesDelight = magnum;               // implicit cast OK. Value = 1 foot.

Siguiendo la norma marco .NET, el formato todo cuerda y el análisis sintáctico es manejado por un FormatProvider externa, que implementa ICustomFormatter. Lamentablemente, esto significa que el valor es en caja cuando se pasa al método de formato, y las necesidades del método de formato para poner a prueba el objeto contra todo tipo de medición conocida antes de que pueda actuar en consecuencia. Internamente, el método de formato simplemente arroja la medición a un valor de distancia de todos modos, así que aquí viene la pregunta ....

Pregunta:

public string Format(string format, object arg, IFormatProvider formatProvider)
{
    Distance distance;           

    // The following line is desired, but fails if arg != typeof(Distance)   
    distance = (Distance)arg;    

    // But the following tedious code works:
    if(arg is Distance)
       distance = (Distance)arg;
    else if(arg is Meters)
       distance = (Distance)(Meters)arg;     // OK. compile uses implicit cast. 
    else if(arg is Feet)
       distance = (Distance)(Feet)arg;       // OK. compile uses implicit cast. 
    else if(arg is Inches)
       distance = (Distance)(Inches)arg;     // OK. compile uses implicit cast. 
    else
        ... // tear you hair out for all 12 measurement types
}

¿Hay alguna solución para esto, o esto es sólo uno de esos inconvenientes insalvables de los tipos de valor?

PD: he comprobado este post , y aunque la cuestión es similar, no es lo que estoy buscando.

¿Fue útil?

Solución

Bueno, es una cuestión de separar la conversión unboxing de la conversión definida por el usuario. Usted quiere tanto esto ocurra - y usted tiene que especificar el tipo de unbox, así como dejar que el compilador de conocimientos cuando se desea una conversión definida por el usuario. La conversión definida por el usuario que se ha recogido en el compilación tiempo, a menos que estés usando tipado dinámico, por lo que las necesidades del compilador para saber qué tipo que está tratando de convertir.

Una opción es tener una IDistance Interfaz , que todas las estructuras de implementar. Entonces es posible que utilices:

IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
    Distance distance = distanceArg.ToDistance();
}

A medida que tenga un valor en caja ya, utilizando una interfaz que no causa el boxeo adicional o algo por el estilo. Cada aplicación puede ToDistance probablemente sólo tiene que utilizar la conversión implícita:

public Distance ToDistance()
{
    return this;
}

... o usted podría hacer que el uso ToDistance conversión.

Otros consejos

Sí, es sólo una de esas cosas que tienes que vivir.

Te encuentras con la misma cosa si usted empuja un entero en un objeto:

int a = 0;
object b = a;
int c = (int)b; // this works
short d = (short)b; // this fails
short e = (short)(int)b; // this works
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top