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
IderivedFromAque contenga los métodos comunes deByC
Parece que esto es imposible por tu pregunta - En
DemiteTparadynamicy llamar dinámicamente los métodos.
La solución más fácil, si puedes usar .Net 4 - En la prueba
Dsi usted trata con unBoC, 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>paraByC, estos pueden llamar los métodos deByCdirectamente. (No pensé en esto yo mismo).
Solo funcionará si el "usuario-fuente" sabe que está tratando conBoC, y no usa el resumenApara usarD<A>. En su lugar, debe utilizarDBoDC. 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> .