2012-05-04 16 views
12

Tengo un conjunto de Clase A y Clase B ambas tienen algunas propiedades. y otra Clase C que tiene sus propias propiedades.Interfaz vs Herencia Múltiple En C#

Cada vez que creo una instancia de la clase C, quiero acceder a todas las propiedades de las tres clases con objClassC.

¿Cómo puedo lograr esto en C#?

I m enfrentan a dos problemas: -

  1. no puedo heredar tanto las clases A, B en la clase C (C# no soporta herencia múltiple)
  2. si uso la interfaz en lugar de Clase A , B (en la interfaz no podemos contiene campos)
+3

Puede usar la composición. También hay [mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –

Respuesta

29

¿Por qué no contienen instancia de la clase A y clase B dentro de la Clase C. Uso Composition

class C 
{ 
//class C properties 
public A objA{get;set;} 
public B objeB{get;set;} 
} 

A continuación, puede acceder

C objc = new C(); 
objc.objA.Property1 = "something"; 
objc.objB.Property1 = "something from b"; 

compruebe el artículo Composition vs Inheritance

EDIT:

si uso Interface inste anuncio de Clase A, B (en la interfaz no podemos contiene campos)

Bueno, las interfaces no pueden contener campos, si se define uno, tendrán error de compilación. Pero las interfaces pueden contener propiedades, con la excepción de que no puede especificar access specifiers, ya que todos los elementos de la interfaz se consideran public. Puede definir las propiedades de la interfaz 'A' y 'B' como:

public interface IA 
{ 
    int Property1 { get; set; } 
} 


public interface IB 
{ 
    int Property2 { get; set; } 
} 

A continuación, puede ponerlas en práctica en la clase C como:

public class C : IA, IB 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 
} 

Más tarde se puede utilizar como:

C objC = new C(); 
objC.Property1 = 0; 
objC.Property1 = 0; 
+4

+1 para la composición sobre la herencia –

+2

@downvoter, no dude en comentar – Habib

+0

si la implementación de IA, IB es necesaria en la clase C, ¿qué se necesita para implementar IA e IB? podemos simplemente definir propiedades sin implementar interfaces ...? –

2

interfaces pueden contener propiedades, es decir .:

public interface IFoo 
{ 
    string Bar { get; set; } 
} 
3

Las interfaces no son una solución a la falta de Herencia Múltiple. Simplemente no hacen las mismas cosas. Lo más cercano que puede obtener es hacer que C sea una subclase de A, y tener una propiedad de tipo B. Quizás si nos dice lo que A, B y C deberían hacer, podemos darle una respuesta que se ajuste mejor a sus necesidades ...

4

Las interfaces pueden tener propiedades, pero si también desea utilizar los métodos, puede ser necesaria la composición o la inyección de dependencia.

Interface A 
{ 
    int PropA {get; set;} 
} 


Interface B 
{ 
    int PropB {get; set;} 
} 

class C : A, B 
{ 

} 

// poner estas declaración en algún método

C c = new C(); 
c.PropA = 1; 
c.PropB = 2; 
1
public interface IAA 
{ 
    string NameOfA { get; set; } 
} 
public class AA : IAA 
{ 
    public string NameOfA{get;set;} 
} 

public interface IBB 
{ 
    string NameOfB { get; set; } 
}  
public class BB : IBB 
{ 
    public string NameOfB{get;set;} 
} 

public class CC : IAA, IBB 
{ 
    private IAA a; 
    private IBB b;    

    public CC() 
    { 
     a = new AA{ NameOfA="a"}; 
     b = new BB{ NameOfB="b"}; 
    } 

    public string NameOfA{ 
     get{ 
      return this.a.NameOfA; 
      } 
     set{ 
      this.a.NameOfA = value; 
      } 
    } 

    public string NameOfB 
    { 
     get{ 
      return this.b.NameOfB; 
     } 
     set{ 
      this.b.NameOfB = value; 
     } 
    } 
} 
1

interfaces no pueden contener campos, pero pueden contener propiedades. En la mayoría de los casos, las propiedades pueden ser utilizados como campos, y no hay ninguna dificultad en decir:

 
interface ISomeProperties 
    {int prop1 {get;set;}; string prop2 {get; set;}} 
interface IMoreProperties 
    {string prop3 {get;set;}; double prop4 {get; set;}} 
interface ICombinedProperties : ISomeProperties, IMoreProperties; 
    { } 

Dado un lugar de almacenamiento del tipo ICombinedProperties, se puede acceder a todas las cuatro propiedades directamente y sin problemas.

Cabe señalar, sin embargo, que hay algunas cosas que se pueden hacer con los campos que no se pueden hacer con las propiedades. Por ejemplo, aunque un campo se puede pasar al Interlocked.Increment, una propiedad no puede; intentar Interlocked.Increment una propiedad copiándolo a una variable, llamando Interlocked.Increment en eso, y luego copiar el resultado de nuevo a la propiedad podría "trabajo" en algunos casos, pero fallaría si dos hilos intentaron hacer lo mismo al mismo tiempo (que sería sea ​​posible, por ejemplo para los dos hilos para leer un valor de 5, el incremento a 6, y luego escribir de nuevo 6, mientras que tiene dos hilos llaman Interlocked.Increment en un campo que fue inicialmente igual a 5 estaría garantizado para producir 7.).

Para evitar esto, puede ser necesario tener la interfaz incluye algunos métodos que realizan un método entrelazado en un campo (por ejemplo, uno podría tener una función que llama al Interlocked.Increment en el campo y devuelve el resultado) y/o incluir funciones que llamar a un delegado especificado con un campo como un parámetro ref (por ejemplo

 
delegate void ActionByRef<T1>(ref T1 p1); 
delegate void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2); 
delegate void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3); 
interface IThing 
{ // Must allow client code to work directly with a field of type T. 
    void ActOnThing(ActionByRef<T> proc); 
    void ActOnThing<ExtraT1>(ActionByRef<T, ExtraT1> proc, ref ExtraT1 ExtraP1); 
    void ActOnThing<ExtraT1, ExtraT2> 
     (ActionByRef<T> proc, ref ExtraT1 ExtraP1, ref ExtraT2 ExtraP2); 
} 

Dada una instancia de la interfaz, se podría hacer algo como:

 
    theInstance.ActOnThing(
    (ref int param) => Threading.Interlocked.Increment(ref param) 
); 

o, si uno tenía variables locales maskValue y xorValue y quería actualizar atómicamente el campo con field = (field & maskValue)^xorValue:

 
    theInstance.ActOnThing(
    (ref int Param, ref int MaskValue, ref int XorValue) => { 
     int oldValue,newValue; 
     do {oldValue = param; newValue = (oldValue & MaskValue)^XorValue; 
     while (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue) != 
      oldValue), 
    ref maskValue, ref xorValue); 
); 

Si había sólo unos pocos tipos de acciones que uno quiere realizar en los campos, sería más simple para incluir simplemente ellos dentro de la interfaz. Por otro lado, el enfoque dado anteriormente permite una interfaz para exponer sus campos de una manera tal como para permitir a los clientes realizar secuencias arbitrarias de acciones sobre ellos.

+0

-1. no aborda la pregunta. – radarbob

+0

@radarbob: Parte de la pregunta tenía que ver con el hecho de que las interfaces no pueden contener campos. Otras respuestas reconocieron que, en muchos casos, uno puede usar propiedades en lugar de campos. Quería ampliar el hecho de que es posible utilizar interfaces incluso cuando uno quiere usar campos de maneras en que las propiedades no son un sustituto aceptable. – supercat

1

considerar cómo las propiedades se exponen de forma diferente al cliente cuando se utiliza la composición vice herencia.

Herencia:

 
    var myCclass = new Cclass; 
    myClass.propertyA; 
    myClass.propertyB; 
    myClass.propertyC; 
    // and so on 

Composición:

var myCclass = new Cclass; 
    myCclass.bClass.propertyB; 
    myCclass.aClass.propertyA; 
    myCclass.propertyC; 

Herencia da una API limpia - una buena cosa.

Composición me obliga a saber algo acerca de la estructura interna de la clase - no es una buena cosa. Esto infringe el law of demeter, mejor conocido como el principio de menor conocimiento.Puede evitar esto teniendo las propiedades de Clase que exponen/devuelven las propiedades de clase Blass & Aclass - y sus referencias de Clase Blass & entonces serían privadas o protegidas en Clase de clase. Y Cclass tiene control total sobre lo que está expuesto en lugar de depender de A & B para no tener material público que no se expuso.

Estoy de acuerdo con @AlejoBrz, las interfaces no son apropiadas aquí.

También doy un guiño a "preferir la composición a la herencia". Pero esto es una pauta, no una regla dura y rápida.