multiple - C#genéricos-¿Puedo hacer que T sea de una de dos opciones?
interfaces generics c# (7)
Supongamos que tengo la siguiente jerarquía de clases:
Class A {...}
Class B : A {...}
Class C : A {...}
Lo que tengo actualmente es
Class D<T> where T : A {...}
pero me gustaría algo de la forma
Class D<T> where T in {B,C}
Esto se debe a algún comportamiento extraño que no soy responsable de donde B y C tienen métodos comunes que no están en A, pero sería bueno poder llamarlos en D en T.
Nota: No tengo acceso a A, B o C para editarlos
¿B y C implementan la misma interfaz? Esa puede ser una mejor ruta.
Algunas opciones:
- Haga una interfaz
IderivedFromA
que contenga los métodos comunes deB
yC
Parece que esto es imposible por tu pregunta - En
D
emiteT
paradynamic
y llamar dinámicamente los métodos.
La solución más fácil, si puedes usar .Net 4 - En la prueba
D
si usted trata con unB
oC
, emitir y llamar
Será revisado por el compilador, y es posible desde .Net 2 - La respuesta de Dan Tao : Cree una implementación específica de
D<T>
paraB
yC
, estos pueden llamar los métodos deB
yC
directamente. (No pensé en esto yo mismo).
Solo funcionará si el "usuario-fuente" sabe que está tratando conB
oC
, y no usa el resumenA
para usarD<A>
. En su lugar, debe utilizarDB
oDC
. Pero creo que este es el caso, de lo contrario no necesitabas los genéricos.
Como no tiene acceso a la fuente, la única respuesta real (a menos que esté dispuesto a perder la seguridad mediante el uso de la dynamic
) es verificar explícitamente la B
/ C
y la conversión.
Debe definir una interfaz para los métodos comunes que se encuentran en B y C (llamémosla Ibc), hacer que B y C implementen esta interfaz, y luego puede escribir:
Class D<T> where T : A, Ibc {...}
El lugar donde se restringe en C # no le permite especificar varias clases como una opción. Además, si especifica múltiples donde contiene, entonces ambos deben ser satisfechos. No hay lógica OR para la restricción. Aquí está la especificación: http://msdn.microsoft.com/en-us/library/bb384067.aspx
Las respuestas de Grzenio te parecen adecuadas. Extraiga el comportamiento común en la interfaz común para B y C. Luego, puede usar esa interfaz como una restricción.
Esto no es directamente posible.
Como otros sugieren, puede definir una interfaz e implementarla tanto en B
como en C
Si esta no es una opción (por ejemplo, si estas clases están fuera de su control), lo que podría sugerir es esta: primero, comience con una clase abstracta que incluya toda la funcionalidad que puede lograr con cualquier T
derivada de A
Luego diga que tiene algunos métodos que existen tanto para B
como para C
que no forman parte de A
En D
puedes hacer que estos métodos abstractos sean implementados por subclases:
public abstract class D<T> where T : A
{
protected T _member;
public void DoSomethingAllTsCanDo()
{
_member.DoSomething();
}
public abstract void DoSomethingOnlyBAndCCanDo();
}
Luego puede heredar de la clase base para cada tipo B
y C
y anular los métodos abstractos para proporcionar la funcionalidad apropiada:
public class DB : D<B>
{
public override void DoSomethingOnlyBAndCCanDo()
{
_member.DoSomethingOnlyBCanDo();
}
}
public class DC : D<C>
{
public override void DoSomethingOnlyBAndCCanDo()
{
_member.DoSomethingOnlyCCanDo();
}
}
Primero, si B y C tienen métodos comunes, es una falla de diseño que no comparten una interfaz. Dicho esto, puedes solucionarlo incluso sin tener acceso a B y C.
Es posible crear una interfaz común. Supongamos que usted tiene:
public class A
{
}
public class B : A
{
public void Start() { }
}
public class C : A
{
public void Start() { }
}
Puedes crear una interfaz común:
public interface IStartable
{
void Start();
}
Y úselo en clases derivadas de B y C:
public class BetterB : B, IStartable
{
}
public class BetterC : C, IStartable
{
}
Es posible que no pueda lograrlo si obtiene las instancias B y C como están, pero se puede considerar si las crea. De hecho, con clases especializadas de B y C, puede usar la interfaz en lugar de D<T>
.