2010-09-29 28 views
8

¿Hay algo malo en usar un operador implícita como la siguiente:operador implícito sobre los tipos genéricos

//linqpad c# program example 
void Main() 
{ 
    var testObject = new MyClass<int>() { Value = 1 }; 

    var add = 10 + testObject; //implicit conversion to int here 
    add.Dump(); // 11 
} 

class MyClass<T> 
{ 
    public T Value { get; set; } 
    public static implicit operator T (MyClass<T> myClassToConvert) 
    { 
     return myClassToConvert.Value; 
    } 
} 

estaba pensando que podía tratar como instancia del objeto como un tipo de valor de esta manera, pero ya que me Nunca he visto un ejemplo de esto, pensé que tal vez había una razón no para hacer algo como esto que alguien podría señalar?

En mi código real estaba pensando en hacer esto como parte de una capa de abstracción de datos, para poder devolver objetos con información que describa los datos subyacentes, pero permitir que el código lógico los trate como un tipo de valor cuando todo necesita saber sobre el valor, y al mismo tiempo mantenerlo todo bien y escribir seguro con los genéricos.

Respuesta

10

Si todas las condiciones siguientes son verdaderas:

  • todos los valores posibles de su tipo MyClass<T> (incluyendo null si no es un tipo de valor!) Mapa a un valor válido de T

  • el operador implícito nunca arroja (ni siquiera para null!)

  • el implicit co nversión tiene sentido semántico y no es confuso para el programador cliente

entonces no hay nada de malo en esto. Por supuesto que podría hacer alguna de estas tres cosas, pero sería un mal diseño. En particular, un operador implícito que arroja puede ser muy difícil de depurar porque el lugar al que se llama no dice que se está llamando.

Por ejemplo, considere que T? no tiene una conversión implícita a T (donde T es, por supuesto, un tipo de valor). Si existiera dicho operador implícito, tendría que arrojarse cuando el T? es nulo, ya que no hay un valor obvio para convertir null en el sentido de tipo de valor .


Déjeme darle un ejemplo en el que tenía problemas para depurar un problema donde el operador implícito tiró:

public string Foo() 
{ 
    return some_condition ? GetSomething() : null; 
} 

Aquí, GetSomething devuelto algo de un tipo que escribí que tiene una conversión implícita definida por el usuario a string. Hice absolutamente seguro que GetSomething nunca podría devolver null, y aun así obtuve un NullReferenceException! ¿Por qué? Debido a que el código anterior es no equivalente a

return some_condition ? (string)GetSomething() : (string)null; 

pero a

return (string)(some_condition ? GetSomething() : (Something)null); 

Ahora se puede ver dónde está el null vinieron!

+0

No estoy seguro de que entiendo la preocupación en torno a los tipos anulables ... Me parece que si tenía n = new MiClase () {} Valor = null; y el código de consumo intentó hacer algo como int i = n; y arrojaría la misma excepción que cualquier elenco malo, nada especial sobre el tipo que se puede anular aquí ¿verdad? – asawyer

+0

@asawyer: Fue solo un ejemplo. Imagine que no hubo 'T?' Y * usted * tuvo que implementar un 'Nullable ' propio. ¿Le daría una conversión implícita a 'T'? Mi respuesta explica por qué no deberías, y por qué el * real * 'T?' No. – Timwi

+0

Veo ahora, es este tipo de preocupaciones lo que provocó la pregunta en primer lugar. Parece que debería estar bien para proceder, pero tenga mucho cuidado. – asawyer

1

Ese es un gran patrón. Solo tenga en cuenta que para usarlo como una variable de tipo T, debe explicitarlo a T, o asignarlo a una variable de tipo T. El reparto se realizará automáticamente en llamadas a métodos y otras cosas (como su ejemplo de adición) que toman un T.

Implicit conversion without assignment?

+0

Eso no es verdad. – Timwi

+0

@Timwi, ¿estás seguro? 'MyClass myClass', en este punto,' myClass. * 'Solo resolverá miembros en' MyClass ', no en' T'. Tendría que hacer como menciones de therootbeer, y hacer '((T) myClass). *' Para acceder a cualquier miembro en 'T'. –

+0

Hice esta misma pregunta hace unos días. http://stackoverflow.com/questions/3703555/implicit-conversion-without-assignment – arootbeer