2012-05-25 14 views
6

Estaba leyendo un poco sobre varianza genérica y todavía no lo entiendo completamente, pero me gustaría saber si hace algo como lo siguiente posible.¿Puede la varianza de C# 4.0 ayudarme a llamar a un constructor de clase base con un upcast?

class A<T> { } 

class B { } 

class C : B { } 

class My1 { 
    public My1(A<B> lessDerivedTemplateParameter) 
    { 
    } 
} 

class My2 : My1 { 
    public My2(A<C> moreDerivedTemplateParameter) 
     : base(moreDerivedTemplateParameter) // <-- compile error here, cannot convert 
    { 
    } 
} 
+1

No soy tan fluido en el varian genérico como me gustaría, por lo tanto, este es un comentario, no una respuesta, pero creo que debe definir 'A ' como 'A ' para hacer esta compilación. – psubsee2003

+3

@ psubsee2003: Creo que solo está permitido para interfaces. – Douglas

+0

interesante, hice su sugerencia y además tuve que hacer A e interfaz, luego compila ... Continuaré y veré si puedo obtener el mismo resultado que estaba buscando, gracias ... –

Respuesta

6

No, porque mientras C hereda de B, A<C> no se heredan de A<B>.

Para entender por qué esto es así, imagínese si A<T> eran lugar List<T>:

class B { } 

class C : B { } 

class D : B { } 

class My1 { 
    public My1(List<B> lessDerivedTemplateParameter) 
    { 
     // This is totally legal 
     lessDerivedTemplateParameter.Add(new D()); 
    } 
} 

class My2 : My1 { 
    public My2(List<C> moreDerivedTemplateParameter) 
     // if this were allowed, then My1 could add a D to a list of Bs 
     : base(moreDerivedTemplateParameter) 
    { 
    } 
} 

Ahora, por otro lado, esto es legal:

interface IA<out T> { 
    public T GetSome(); 
} 

class B { } 

class C : B { } 

class D : B { } 

class My1 { 
    public My1(IA<B> lessDerivedTemplateParameter) 
    { 
     // This is totally legal 
     var someB = lessDerivedTemplateParameter.GetSome(); 
    } 
} 

class My2 : My1 { 
    public My2(IA<C> moreDerivedTemplateParameter) 
     // This is allowed, because an A<C> only *produces* C's (which are also B's) 
     // so the base class (which consumes B's, and doesnt care if they are C's) 
     // can use an IA<C> 
     : base(moreDerivedTemplateParameter) 
    { 
    } 
} 
+0

Esto es correcto, pero se pierde el objetivo de la pregunta. Él * sabe * que la configuración actual no funciona, y quiere saber si puede aprovechar la varianza para cambiar esa situación. Acaba de repetir lo que ya sabe. – dlev

+0

@dlev He agregado una ilustración de lo que * does * work –

+0

Nice. +1 de hecho. – dlev

2

Puede declarar una como una interfaz con un parámetro de tipo contravariante y compilará:

internal interface A<out T> 
    { 
    } 

    internal class B 
    { 
    } 

    internal class C : B 
    { 
    } 

    internal class My1 
    { 
    public My1(A<B> lessDerivedTemplateParameter) 
    { 
    } 
} 

internal class My2 : My1 
{ 
    public My2(A<C> moreDerivedTemplateParameter) 
     : base(moreDerivedTemplateParameter) 
    { 
    } 

} 
+1

Lo más importante a tener en cuenta aquí es que esto limita a A solo a producir (y no consumir) tipo T. –

+0

@ChrisShain, y esa es la conexión con el significado de 'salir' ¿no? –

+0

@ AaronAnodide eso es correcto –

Cuestiones relacionadas