9

dado esta clase con un operador de conversión implícita:¿Hay alguna forma de hacer fundición de tipo implícita dinámica en C#?

public class MyDateTime 
{ 
    public static implicit operator MyDateTime(System.Int64 encoded) 
    { 
     return new MyDateTime(encoded); 
    } 

    public MyDateTime(System.Int64 encoded) 
    { 
     _encoded = encoded; 
    } 
    System.Int64 _encoded; 
} 

ahora puedo hacer lo siguiente:

long a = 5; 
MyDateTime b = a; 

pero no el siguiente:

long f = 5; 
object g = f; 
MyDateTime h = g; 

Esto da un tiempo de compilación:

No se puede convertir implícitamente el tipo 'objeto' a 'MiTiempoTiempo'.

Tiene sentido para mí.

Ahora modifique el ejemplo anterior de la siguiente manera:

long f = 5; 
object g = f; 
MyDateTime h = (MyDateTime)g; 

Este compila bien. Ahora obtengo un tiempo de ejecución InvalidCastException:

No se puede convertir el objeto del tipo 'System.Int64' para escribir MyDateTime '.

Esto me dice que los operadores de colada implícita C# se aplican solo en tiempo de compilación, y no se aplican cuando el tiempo de ejecución de .NET está intentando lanzar dinámicamente un objeto a otro tipo.

Mis preguntas:

  1. Estoy en lo correcto?
  2. ¿Hay alguna otra forma de hacerlo?

Por cierto, la aplicación completa es que estoy usando Delegate.DynamicInvoke() llamar a una función que toma un parámetro MyDateTime, y el tipo de argumento que estoy pasando a DynamicInvoke es mucho.

Respuesta

13

Estoy en lo correcto?

Sí, sí lo eres. Para ser quisquilloso, debería decir "conversión implícita definida por el usuario" en lugar de "conversión implícita": un reparto es (casi) siempre explícito. Pero su deducción de que la resolución de sobrecarga elige qué conversión definida por el usuario para llamar a en el tiempo de compilación y no a en el tiempo de ejecución es correcta.

¿Hay alguna otra forma de hacerlo?

Sí. En C# 4 si escribe su "objeto" como "dinámico", iniciamos nuevamente el compilador en tiempo de ejecución y realizamos todo el análisis en los operandos como si sus tipos de tiempo de compilación fueran los tipos de tiempo de ejecución actuales.Como se puede imaginar, esto no es barato, aunque somos muy inteligentes sobre el almacenamiento en caché y la reutilización de los resultados en caso de que haga esto en un círculo cerrado.

+0

Solo por curiosidad, ¿cuáles son las razones por las que los operadores no se comportan más como métodos en tiempo de ejecución? Dada tu respuesta, se siente como si fueran meros azúcares sintácticos y no mucho más. En mi opinión, haría C * aún más poderoso si este tipo de operadores se promocionan como miembros de primera clase de cualquier tipo (lo que significa que se convierten en parte de todas las otras bondades orientadas a objetos como herencia, anulación e interconexión). ¿Aprovechar estos en tiempo de ejecución de forma predeterminada implica cambios importantes en el diseño y la implementación del lenguaje? – MarioDS

+1

@MDeSchaepmeester: Tiene razón en que hay un poco de desconexión aquí. Compare el diseño de int a decimal, por ejemplo. Puede decir 'Func add = decimal.Add;' pero no hay forma de hacer lo mismo para int; tienes que decir 'Func add = (x, y) => x + y'. Hubiera sido agradable, creo, si todos los tipos incorporados se hubieran diseñado como Decimal, y luego el tiempo de ejecución o el compilador podrían elegir reducirlos a operaciones más fundamentales por motivos de rendimiento. Pero este tipo de consistencia realmente se sigue de una mentalidad "funcional". –

+1

@MDeSchaepmeester: sospecho que los diseñadores originales del tiempo de ejecución simplemente no estaban pensando en ese tipo de abstracción funcional unificadora al diseñar el sistema de tipos y las operaciones en tipos incorporados. Y, por supuesto, también es extraño que el decimal tenga un operador + y un método Add. ¡Y ni siquiera me pidas que inicie la docena de formas para representar la operación de igualdad! Es un poco un desastre realmente. La próxima vez que diseñe un marco desde cero, consiga esto pronto. –

-2

Sé que esto es una cuestión más antiguo, pero en caso de que alguien se tropieza otra persona sobre el mismo problema, esto va a compilar y ejecutar bien:

long f = 5; 
object g = f; 
MyDateTime h = g as MyDateTime; 
+0

Funcionará bien en el sentido de que no arrojará una 'InvalidCastException', sin embargo' h' será 'null', que no es lo que el OP quiere o espera. – MarioDS

Cuestiones relacionadas