2010-02-13 14 views
8

Digamos que tengo una interfaz como que:restricciones de tipo de implementaciones de los miembros de las interfaces genéricas no genéricos en C#

interface IAwesome 
{ 
    T DoSomething<T>(); 
} 

¿Hay alguna manera de poner en práctica el método HacerAlgo con tipo de restricción? Obviamente, esto no funcionará:

class IncrediblyAwesome<T> : IAwesome where T : PonyFactoryFactoryFacade 
{ 
    public T DoSomething() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Esto, obviamente, no va a funcionar porque este HacerAlgo() no va a satisfacer plenamente el contrato de IAwesome - que sólo funciona para un subconjunto de todos los posibles valores del parámetro de tipo T. ¿Hay alguna forma de hacer que este trabajo no tenga algo de "magia negra" (que es lo que voy a hacer como último recurso si la respuesta es no)?

Honestamente, no creo que sea posible, pero me pregunto qué piensan.

EDITAR: La interfaz en cuestión es System.Linq.IQueryProvider por lo que no se puede modificar la propia interfaz.

Respuesta

7

No, esto no puede funcionar por diseño, ya que significaría que el contrato para IAwesome no se satisfaría (completamente).

, siempre y cuando IncrediblyAwesome<T> implementos IAwesome, se le permite hacer esto:

IAwesome x = new IncrediblyAwesome<Something>() 

Obviamente, con su limitación adicional, esto no podría funcionar, ya que el usuario de IAwesome no puede conocer de las restricciones establecidas en él .

En su caso, la única solución que se me ocurre es la siguiente (en tiempo de ejecución haciendo la comprobación):

interface IAwesome { // assuming the same interface as in your sample 
    T DoSomething<T>(); 
} 

class IncrediblyAwesome<TPony> : IAwesome where TPony : PonyFactoryFactoryFacade { 
    IAwesome.DoSomething<TAnything>() { 
     return (TAnything)((object)DoSomething()); // or another conversion, maybe using the Convert class 
    } 

    public TPony DoSomething() { 
     throw new NotImplementedException(); 
    } 
} 
+0

Sí, eso es a lo que le tenía miedo. –

+1

Has usado "T" para significar tres cosas diferentes pero estrechamente relacionadas en este código. Eso es muy confuso ¿Puedes hacer que al menos uno de ellos tenga otro nombre? –

+0

Sí, lo siento, copiar y pegar es malo ... Reparado - gracias por la pista. ;) – Lucero

2

¿Algo así no soluciona el problema?

interface IAwesome<U> 
{ 
    T DoSomething<T>() where T : U 
} 

class IncrediblyAwesome<T> : IAwesome<PonyFactoryFactoryFacade> 
{ 
    public T DoSomething() 
    { 
     throw new NotImplementedException(); 
    } 
} 

No estoy seguro si esto compila.

+0

Desafortunadamente, la interfaz en cuestión no está definida por mí, es parte del framework .NET (System.Linq.IQueryProvider) así que realmente no puedo poner restricciones de tipo en el inteface Gracias por la sugerencia, sin embargo. –

+0

¿Se puede salir con la increíble cantidad heredando IQueryProvider? ¿O eso rompería tu código? – Zyphrax

+0

Eso tampoco ayudaría porque no puede restringir un método existente en una interfaz; todas las garantías hechas por la interfaz base deben seguir siendo ciertas para todos los descendientes e implementadores (por contrato, por supuesto, usted puede hacer comprobaciones de tiempo de ejecución si es necesario). – Lucero

1

Como ya se ha mencionado, esta solución no puede funcionar.

Por otra parte, el ejemplo viola el contrato de otra manera: Una instancia de IncrediblyAwesome siempre está ligada a un descendiente de PonyFactoryFactoryFacade específica (por cierto, sería muy interesados ​​en los efectos de este :-) clase). Por lo tanto, la implementación concreta de DoSomething sería no sea un método genérico como se especifica en la interfaz, pero siempre devuelva un solo tipo. Usted Couln't escritura:

IAwesome a = new IncrediblyAwesome<SomePonyFacadeFactory1>(); 
SomePonyFacadeFactory2 facade2 = a.DoSomething<SomePonyFacadeFactory2>(); 

a pesar de que ambas fachadas-fábricas decend de PonyFactoryFactoryFacade ...

Otro comentario: Me quedo lejos de fundición de la magia negro, ya que estos problemas son inherentes a su diseño y no solo una falla de C# ...

Cuestiones relacionadas