2010-09-28 10 views

Respuesta

9

¿Conveniencia?

Más o menos, sí. Considere el caso de cuando tiene un objeto similar a un número (por ejemplo, un Complex) en el que hace cálculos. Claramente, la escritura de código, tales como:

Complex result = c1 * new Complex(2) + new Complex(32); 

es muy molesto y difícil de leer. Las conversiones implícitas ayudan aquí (una alternativa serían las sobrecargas del operador en este ejemplo, pero eso generaría muchas sobrecargas similares).

¿Hay una pauta para esto?

Proporcione la menor cantidad de conversiones implícitas posible, ya que pueden ocultar problemas. La conversión implícita reduce la explicitud en la misma cantidad por la cual aumentan la concisión. Algunas veces esto es bueno, pero a veces no.

Me parece que lo mejor para restringir las conversiones implícitas a muy tipos similares, como los objetos de números, como en el ejemplo anterior: un int esencialmente es-un Complex (desde un punto de vista matemático, incluso si no está modelada a través herencia), por lo tanto, una conversión implícita tiene sentido.

En VB, una conversión implícita se llama “Widening” (en contraposición a Narrowing, que es explicit) y esto lo describe así: no se pierde información en el curso de la conversión.

Además, un operador es esencialmente una función de constructor y tiene (algunas de) las ventajas habituales de una función de constructor sobre un constructor: es decir, puede reutilizar valores almacenados en caché en lugar de crear siempre instancias nuevas.

Considera mi ejemplo de Complex. Es posible que queramos almacenar en caché los valores para los números complejos se usan con frecuencia:

Class Complex { 
    // Rest of implementation. 

    private static Complex[] cache = new[] { 
     new Complex(-1), new Complex(0), new Complex(1) }; 

    public implicit operator Complex(int value) { 
     if (value >= -1 && value <= 1) 
      return cache[value]; 
     else 
      return new Complex(value); 
    } 
} 

Por supuesto, si este micro-optimización es eficaz, es otra cuestión.

+0

Gracias, ¿cómo lo harías para las sobrecargas del operador que ayudarían al tipo Complejo? Necesita poder editar el tipo int, ¿verdad? –

+0

@Joan: No, ya que puede implementar operadores en ambas direcciones: * desde * su tipo personalizado y * a * su tipo personalizado. En mi ejemplo, simplemente haga que 'Complex' implemente un operador' implicit operator Complex (int value) '. –

+0

Gracias, lo entiendo ahora. –

3

El uso de conversiones implícitas/explícitas es una cuestión de conveniencia y una que muchas pautas de programación sugieren evitar en favor de los métodos explícitos ConvertToXXX.

Uno de los problemas es que el uso de conversiones implícitas/explícitas sobrecarga adicionalmente las funciones del operador de conversión.Se le da el doble propósito de

  • vistas a un mismo objeto a través de un tipo/interfaz diferente en la jerarquía del objeto
  • coverting el objeto a un nuevo tipo completo

Desafortunadamente C# ya lo hace el segundo en otras áreas (con primitivos y boxeo).

1

Personalmente, yo uso las conversiones cuando sé que los RHS pueden convertirse en un miembro estático de una clase (como decir color = "red" dar a entender color = Colors.Red)

utilizo el nuevo operador cuando pretendo crear en realidad una nueva instancia.

2

Si dos clases deben ser convertibles entre sí, pero no comparten una interfaz de una clase base que permita este comportamiento automáticamente, usted usaría las conversiones. Las conversiones implícitas deben nunca tienen una posibilidad de pérdida de datos; a menudo se consideran conversiones "ampliadas". Por ejemplo, convertir un int en un long es una conversión cada vez más amplia, y no hay ningún problema inherente en que la conversión sea implícita. Las conversiones explícitas pueden implicar la posibilidad de pérdida de datos; un long puede o no ser convertible a int, dependiendo de su valor.

Un truco que he usado con las conversiones implícitas es convertir clases en espacios de nombres diferentes entre sí cuando no tenía otra opción razonable. Por ejemplo, un servicio WCF devuelve un objeto AuthenticationToken que necesito pasar a un servicio WCF en un espacio de nombres diferente. Ambos tienen este objeto AuthenticationToken, y la conversión constante hubiera sido un problema. Mi solución implicó usar public static implicit operator en una clase parcial para agregar la funcionalidad para convertir en cada sentido.

+0

La idea de que el lenguaje de "conversiones implícitas no debería causar pérdida de datos" es popular, pero creo que una noción mejor sería "* ida y vuelta * las conversiones implícitas no deberían causar la pérdida de datos". Si un 'SimpleType' representa un' ComplicatedType' donde las propiedades "complicadas" coinciden con los valores predeterminados, las conversiones de ampliación deberían permitirse solo de 'SimpleType' a' ComplicatedType', pero si representa un 'ComplicatedType' donde los valores de las propiedades complicadas son desconocidos , la conversión implícita debería, si acaso, solo permitirse en el otro sentido. – supercat

5

Una de las razones detrás de la utilización de la conversión implícita con tipos tan simples como XName es, creo, la conveniencia de los métodos de llamada.

Por ejemplo, puede escribir

var info = root.Elements ("user").Element ("info").Value; 

Simplicidad en la extracción de datos es lo LINQ se trata, y si teníamos que escribir

var info = root.Elements (new XName ("user")).Element (new XName ("info")).Value; 

incluso para consultas sencillas, le LINQ ser totalmente vale la pena por los más complejos?

Otro tema importante aquí es que los XNames están atomizados. Ver MSDN:

Se garantiza que los objetos XName sean atomizados; es decir, si dos objetos XName tienen exactamente el mismo espacio de nombre y exactamente el mismo nombre local, compartirán la misma instancia. Los operadores de igualdad y comparación también se proporcionan explícitamente para este propósito.

Entre otras ventajas, esta característica permite una ejecución más rápida de las consultas. Al filtrar en el nombre de elementos o atributos, las comparaciones expresadas en predicados usan comparación de identidad, no comparación de valores. Es mucho más rápido determinar que dos referencias se refieren al mismo objeto que comparar dos cadenas.

No se puede proporcionar la atomización en el constructor, pero definir una conversión le permite escoger objeto correspondiente de la piscina y devolverlo como si se tratara de una nueva instancia.

Cuestiones relacionadas