2012-02-29 16 views
6

pregunta relacionada: Accessing a Class property without using dot operatorcasting Mi clase de Int64, etc Doble

He creado una clase llamada MyDouble se parece a esto

class MyDouble 
{ 
    double value; 
    //overloaded operators and methods 
} 

soy capaz de hacer todo tipo de operaciones en MiDouble. Ejemplos:

MyDouble a = 5.0; 
a += 3.0; 
...etc 

Sin embargo, esto todavía genera un error

MyDouble a = 5.0; 
long b = (Int64)a; //error 
long b = (int64)a.value; //works 

Como puedo definirlo de tal manera que una operación como (Int64)a se convierte automáticamente en (Int64)a.value? No quiero que el usuario tenga que preocuparse por la existencia de la propiedad value.

+0

¿Por qué usas tanto 'long' como' Int64'? Uno es un aloas para el otro y creo que la forma más idiomática es usar los alias si existen en lugar de los nombres de tipo. – Joey

Respuesta

9

Para que esta conversión funcione, necesitará un explicit conversion a Int64.

Este sería el resultado:

class MyDouble 
{ 
    double value; 

    public static explicit operator Int64(MyDouble value) 
    { 
     return (Int64)value.value; 
    } 
} 
+0

Perfecto, gracias. – xbonez

+0

¿Por qué debería ser explícito? Una conversión implícita también funciona y el elenco se vuelve opcional. – Jay

+0

@Jay Usted * podría * hacer una operación implícita, pero el OP mostró incluyendo el operador de conversión. Personalmente, tiendo a tratar de evitar las conversiones implícitas a menos que tengan mucho sentido (sin embargo, convertir implícitamente de doble a largo parece una mala idea). –

1

Hay una conversión explícita de doble a Int64, pero no de su clase para Int64. todo lo que necesitas hacer es definir uno. O bien, si tiene una conversión de su clase al doble, lo que supongo que hace, puede hacer esto:

largo x = (largo) (doble) a;

Sin embargo, eso es engorroso; Definiría el operador de conversión explícito.

La conversión debe ser explícita, no implícita, a menos que tenga un buen motivo para hacerlo explícito.

La conversión definida por el lenguaje de doble a larga es explícita porque la conversión podría causar pérdida de información. Puede perder información con esta conversión porque hay algunos dobles, como 0.5, que no se convierten exactamente en largos. Esto se llama conversión de estrechamiento .

Con las conversiones definidas por idioma, las conversiones reducidas son explícitas. Si estuvieran implícitos, los programadores podrían perder accidentalmente información asignando un valor de un tipo a una variable de otro tipo. Definir esta conversión como implícita viola ese principio totalmente sensato, por lo que tendría que haber algún caso convincente para hacerlo.

Aquí hay un ejemplo que muestra el valor de este principio. Si el estrechamiento de las conversiones fuera implícito, el código sería más frágil. Suponga que la conversión doble a int es implícita:

class Family 
{ 
    ICollection<Person> Children { get; set; } 
} 

int GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Sum(f => f.Children.Count)/families.Count(); 
} 

void SomeMethod(IEnumerable<Family> families) 
{ 
    int averageNumberOfChildren = GetAverageNumberOfChildren(families); 
    //... 
} 

¡Uy! Tenemos un error! GetAverageNumberOfChildren debería devolver un doble! ¡Arreglamos!

double GetAverageNumberOfChildren(IEnumerable<Family> families) 
{ 
    return families.Average(f => f.Children.Count); 
} 

¡Whew, todo compila y funciona! ¡Muy contenta de haber atrapado ese error!

Pero, lamentablemente, no. ¡Todavía tenemos un error!SomeMethod convierte implícitamente el doble en un int, por lo que donde el valor esperado podría ser 2.4, el valor real es 2.

Porque la conversión doble a int es explicita, el compilador nos salva de nosotros mismos. Después de reparar GetAverageNumberOfChildren, , el programa erróneo no se compila.

Ahora, si su clase MyDouble tenía alguna validación que limita a valores enteros con un rango igual o menor que el rango de long, entonces sería seguro para realizar la conversión implícita. Pero en ese caso, por supuesto, debe usar long, no double.

1

Una conversión implícita funcionará tan bien como una conversión explícita.

public static implicit operator long(MyDouble m) 
{ 
    return (long) m.value; 
} 

Con esto en su lugar que puede hacer:

long b = (Int64) a; 

o simplemente

long b = a; 

Esto es sólo para ilustrar que la conversión no tiene que ser explícita. Como se señaló, sin embargo, debe ser explícito debido a la posibilidad de pérdida de datos.

+0

Esto es cierto, pero peligroso. Vea mi respuesta editada para una explicación. – phoog

+0

@phoog Entiendo. Solo estaba teniendo problemas con el lenguaje "usted * necesita * una conversión explícita". – Jay

+0

Bastante justo; Solo pensé que, si estamos discutiendo la existencia de conversiones implícitas, sería conveniente analizar las razones para hacer que las conversiones de angostamiento sean explícitas. De lo contrario, alguien podría tener la tentación de implementar una conversión que debería ser explícita como una conversión implícita "porque es más fácil" o "porque hace que mi código sea más limpio", sin tener en cuenta la mayor probabilidad de escribir programas defectuosos. – phoog