2010-04-28 17 views
13

Una vez definida esta interfaz:Pregunta sobre C# 4.0 genéricos de covarianza

public interface IInputBoxService<out T> { 
    bool ShowDialog(); 
    T Result { get; } 
} 

¿Por qué el trabajo siguiente código:

public class StringInputBoxService : IInputBoxService<string> { 
    ... 
} 

... 

IInputBoxService<object> service = new StringInputBoxService(); 

y esto no ?:

public class IntegerInputBoxService : IInputBoxService<int> { 
    ... 
} 

... 

IInputBoxService<object> service = new IntegerInputBoxService(); 

¿Tiene algo que ver con que int sea un tipo de valor? Si es así, ¿cómo puedo evitar esta situación?

Gracias

+0

¿Ha intentado utilizar Int32 – Strelok

+1

No, pero por lo que tengo entendido que daría lugar a la misma int es un alias para?. Int32. –

Respuesta

14

Sí, absolutamente tiene que ver con int ser un tipo de valor. La varianza genérica en C# 4 solo funciona con tipos de referencia. Esto se debe principalmente a que las referencias siempre tienen la misma representación: una referencia es solo una referencia, por lo que el CLR puede usar los mismos bits para algo que sabe que es una referencia de cadena como para una referencia de objeto. El CLR puede asegurarse de que el código sea seguro y usar un código nativo que solo conozca IInputBoxService<object> al pasar un IInputBoxService<string> - el valor devuelto por Result será representacionalmente compatible (¡si tal término existe!).

Con int =>object tendría que haber boxeo, etc., para que no termine con el mismo código, lo que básicamente arruina la varianza.

EDIT: La especificación C# 4.0 dice esto en la sección 13.1.3.2:

El propósito de anotaciones de varianza es para proporcionar más indulgentes (pero todavía seguros tipo) conversiones a la interfaz y delegar tipos . Para este fin, las definiciones de implícita (apartado 6.1) y conversiones explícitas (§ 6.2) hacen uso de la noción de varianza-convertibilidad, que es define como sigue: Un tipo T es de varianza-convertible a un tipo T si T es o bien una interfaz o un tipo de delegado declarado con los parámetros de tipo variante de t, y para cada tipo de variante parámetro Xi una de las siguientes sostiene:

  • Xi es covariante y un implícita referencia o identidadexisteconversión de Ai a Bi

  • Xi es contravariant y un referencia o identidad implícita conversión existe de Bi a Ai

  • Xi es invariante y existe una conversión de identidad de Ai a Bi

Esto no significa que sea terriblemente obvio, pero básicamente existen conversiones referencia sólo será entre los tipos de referencia, que solo deja conversiones de identidad (es decir de un tipo a sí mismo).

En cuanto a las soluciones: creo que tendrías que crear tu propia clase de contenedor, básicamente. Esto puede ser tan simple como:

public class Wrapper<T> 
{ 
    public T Value { get; private set; } 
    public Wrapper(T value) 
    { 
     Value = value; 
    } 
} 

Es bastante desagradable, aunque :(

+0

Estaba pensando que ese era el caso, pero no puedo encontrar una referencia. ¿Conoce algún enlace msdn que mencione que las varianzas solo funcionan con tipos de referencia? –

+0

¿Qué tal esto? Http: //blogs.msdn. com/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx - Use Ctrl + F para encontrar "Un par de reglas importantes para recordar" y encontrará la entrada. –

+0

¿Hay alguna alternativa? ? Java define para todos tipos de referencia primitivos también, así que en lugar de hacer algo puedo hacer algo , que resolvería este problema. –