2010-05-03 7 views
12

Similar a this Java question. Me gustaría especificar que una variable implemente múltiples interfaces. Por ejemplo¿Hay alguna manera de declarar una variable que implementa múltiples interfaces en .Net?

private {IFirstInterface, ISecondInterface} _foo; 

public void SetFoo({IFirstInterface, ISecondInterface} value) 
{ 
    _foo = value; 
} 

Requisitos:

  • que no tienen la posibilidad de añadir una interfaz para la mayoría del tipo que se pasa a Foo. Por lo tanto, no puedo crear una tercera interfaz que herede de IFirstInterface e ISecondInterface.
  • Me gustaría evitar que la clase contenedora sea genérica si es posible porque el tipo de Foo no tiene mucho que ver con la clase y es probable que el usuario no lo sepa en tiempo de compilación.
  • Necesito usar foo para acceder a los métodos en ambas interfaces más adelante.
  • Me gustaría hacer esto de forma segura para el compilador, es decir, no intentar enviar contenido a la interfaz antes de intentar usarlo. Si foo no implementa ambas interfaces, un poco de funcionalidad no funcionará correctamente.

¿Esto es posible?

Editar: He querido esto un par de veces por varias razones. En este caso, es porque estoy cambiando un conjunto de propiedades de ObservableCollections a ReadOnlyObservableCollections. Tengo una clase de ayuda que crea una proyección desde una fuente ObservableCollection a otra Colección. Como ReadOnlyObservableCollection no hereda de ObservableCollection y solo necesito operaciones en IList e INotifyCollectionChanged, esperaba almacenar mi colección de origen como una combinación de estas dos interfaces en lugar de requerir una ObservableCollection.

+1

usted está fuera de suerte. – ChaosPandion

+2

Respuesta corta: no. No sin definir una tercera interfaz que hereda de IFirstInterface e ISecondInterface. – Anthony

+2

Mi único pensamiento es que podría tener la misma instancia que dos variables de interfaz? ¿En qué circunstancia necesitó esto? ¿Podrías darnos una idea de lo que estabas haciendo donde necesitabas algo como esto? –

Respuesta

13

Si desea limitar su método de SetFoo tomar únicos parámetros que implementan estas dos interfaces, entonces usted está en suerte:

public void SetFoo<T>(T value) where T : IFirstInterface, ISecondInterface 
{ 
    _foo = value; 
} 

A partir de ahora, cada vez que desee acceder a su _foo miembro como una de estas dos interfaces, solo tendrá que acceder mediante conversiones: (IFirstInterface)_foo o (ISecondInterface)_foo, respectivamente.

Dijiste que te gustaría evitar recurrir a los moldes por seguridad en tiempo de compilación; pero creo que si encuentra una manera de asegurarse de que _foo se inicialice usando SetFoo arriba, puede transmitir todo lo que quiera con tranquilidad.


Me acabo de dar cuenta de la siguiente se describe algo que se especifiquen en la pregunta que no quiere hacer.Entonces, digo, ve con lo de arriba.

Otra idea sería, ya que parece que este objeto _foo es un miembro de la clase (Estoy basando esta suposición en el _ en el nombre de la variable), se puede definir la clase de esta manera:

class YourClassThatHasAFoo<T> where T : IFirstInterface, ISecondInterface { 
    private T _foo; 

    public void SetFoo(T value) { 
     _foo = value; 
    } 
} 

Si esto realmente tiene sentido depende, obviamente, de su situación específica. Definitivamente tendrá que pensarlo detenidamente, ya que las clases con restricciones como esta a veces provocan problemas que podría no haber esperado en el futuro (como el SetFoo ahora debe tomar tomar un parámetro del tipo T, no solo cualquier clase que implemente tus dos interfaces).

+0

Usted, señor, obtenga una galleta de oro. ¡Este código es muy útil! –

+0

Tenga en cuenta que '(IFirstInterface) _foo' es frágil. Si elimina 'IFirstInterface' de sus restricciones para' T', se convierte en un molde en tiempo de ejecución. Pero puedes, por ej., haga 'IFirstInterface _fooFirst = _foo' o [use otros trucos para asegurarse de obtener un molde de compilación/estática] (http://stackoverflow.com/q/3894378/429091). – binki

2

Una variable en .NET tiene un tipo, y los tipos pueden implementar múltiples interfaces. Algo como esto:

public interface Interface1 { } 
public interface Interface2 { } 
public class SupportsMuliple : Interface1, Interface2 { } 

Pero a partir de su pregunta parece que usted quiere tener una variable implementar múltiples interfaces sin tener un tipo que implementa las interfaces. Esto no es realmente posible, pero podrías generar un tipo sobre la marcha que implemente las interfaces y oculte el hecho de que hay un tipo real que hace la magia. La biblioteca burlona moq hace esto usando Castle DynamicProxy.

+0

Gracias por su respuesta. Los tipos que implementan las interfaces ya existen, solo necesito una forma de almacenarlos y usarlos de una manera independiente de la implementación. –

5

No, no hay forma de garantizar de forma declarativa que una instancia en particular implemente más de una interfaz.

Una opción PODRÍA ser posible usando genéricos, aunque esto solo funcionaría para una función en lugar de una propiedad.

public void Foo<T>(T arg) 
    where T : IFirstInterface 
    where T : ISecondInterface 
{ 
    ... 
} 

El uso de la inferencia de tipos, debe ser capaz de llamar así:

ConcreteType bar = new ConcreteType(); // this implements both 

Foo(bar); 
1

Es posible definir interfaces de modo que las combinaciones arbitrarias de ellos pueden ser necesarios y utilizados en la moda con seguridad de tipos . La clave es definir una interfaz ISelf (Of Out T), cuyo miembro, Self, es una propiedad por la cual el objeto se devuelve a sí mismo como T, y luego para cada interfaz IFoo, declara un genérico correspondiente de la forma IFoo (Of Out T), que hereda de IFoo e ISelf (Of T). Una clase Wowzo que implementa el propio (de Wowzo), IFoo (de Wowzo), IBar (de Wowzo), y IBoz (de Wowzo), implementará IFoo (de IBar), IBar (de IFoo), IFoo (de IBoz (de IBar)), IFoo (Of IBar (Of IFoo) (Of IBar (Of IBoz (Of IBar))))), etc. y, de ser necesario, pueden ser encasillados a dicho tipo. Si Thing es un IFoo (Of IBar (Of IBoz)), uno puede usarlo directamente como IFoo, o usar Thing.Self como un IBar, o usar Thing.Self.Self como un IBoz.

Ejemplo de cómo componer tres interfaces juntos de esta manera con C#:

public interface ISelf<out T> 
{ 
    T Self { get; } 
} 
interface IA { } 
interface IA<T> : IA, ISelf<T> { } 
interface IB { } 
interface IB<T> : IB, ISelf<T> { } 
interface IC { } 
interface IC<T> : IC, ISelf<T> { } 
class ConcreteThing 
    : IA<ConcreteThing> 
    , IB<ConcreteThing> 
    , IC<ConcreteThing> 
{ 
    public ConcreteThing Self => this; 
} 
public class ReferencingObject 
{ 
    IA<IB<IC>> Thing { get; } 

    void Method() 
    { 
     IA a = Thing; 
     IB b = Thing.Self; 
     IC c = Thing.Self.Self; 
    } 
} 
Cuestiones relacionadas