接口与C#中的多重继承

时间:2012-05-04 11:08:20

标签: c# .net interface multiple-inheritance

我有一组A类和B类都有一些属性。和另一个有自己特性的C类。

每当我创建一个C类实例时,我想用objClassC访问所有三个类的所有属性。

我如何在C#中实现这一目标?

我面临两个问题: -

  1. 我不能继承C类中的A,B类(C#不支持多重继承)
  2. 如果我使用Interface而不是A类,B(在界面中我们不能包含字段)

7 个答案:

答案 0 :(得分:29)

为什么不在C类中包含A类和B类实例。使用Composition

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

然后你可以访问

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

查看文章Composition vs Inheritance

编辑:

  

如果我使用Interface而不是A类,B(在接口中我们不能   包含字段)

嗯,接口不能包含字段,如果定义了一个字段,则会出现编译错误。但是接口可以包含属性,但不能指定access specifiers,因为接口的所有元素都被视为public。您可以将接口“A”和“B”的属性定义为:

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


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

然后你可以在C类中实现它们,如:

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

稍后您可以将它们用作:

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

答案 1 :(得分:4)

接口可以具有属性,但如果您还想使用这些方法,则可能需要进行合成或依赖注入。

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


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

class C : A, B
{

}

//将这些陈述放在某种方法中

C c = new C();
c.PropA = 1;
c.PropB = 2;

答案 2 :(得分:3)

接口不是缺少多重继承的解决方案。他们只是不做同样的事情。你可以得到的最接近的是使C成为A的子类,并具有类型B的属性。 也许如果你告诉我们A,B和C应该做什么,我们可以给出一个更符合你需求的答案......

答案 3 :(得分:2)

接口可能包含属性,即:

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

答案 4 :(得分:2)

考虑在使用继承副组合时,属性如何以不同方式暴露给客户端。

继承:

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

成分:

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

继承提供了更清晰的API - 一件好事。

作文要求我了解班级的内部结构 - 这不是一件好事。这违反了law of demeter - 更为人所知的最少知识原则。您可以通过具有一对一暴露/返回Bclass&的Cclass属性来解决这个问题。 Aclass属性 - 和你的Bclass&然后,Aclass引用将是私有的或受Cclass保护。 AND Cclass完全控制暴露的内容,而不是依赖于A& B没有公开的东西,你没有暴露。

I agree with @AlejoBrz,这里的接口不合适。

我也赞同“更喜欢构图而不是继承”。但这是一个指导方针,而不是一个硬性规则。

答案 5 :(得分: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;
        }
    }
}

答案 6 :(得分:1)

接口不能包含字段,但它们可以包含属性。在大多数情况下,属性可以像字段一样使用,并且说:

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

给定ICombinedProperties类型的存储位置,可以直接访问所有四个属性而不会大惊小怪。

但应该注意的是,对于无法用属性完成的字段,可以做一些事情。例如,虽然字段可以传递给Interlocked.Increment,但属性不能;通过将属性复制到变量来尝试Interlocked.Increment属性,在其上调用Interlocked.Increment,然后将结果复制回属性可能在某些情况下“起作用”,但如果两个线程尝试同时做同样的事情(例如,两个线程都可以读取值5,将其增加到6,然后回写6,而有两个线程在最初等于的字段上调用Interlocked.Increment 5将保证产生7。)。

为了解决这个问题,可能需要让接口包含一些方法,这些方法可以在字段上执行互锁方法(例如,可以在字段上调用Interlocked.Increment并返回结果的函数)和/或包含将使用字段作为ref参数调用指定委托的函数(例如

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);
}

给定接口的实例,可以执行以下操作:

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

或者,如果其中包含局部变量maskValuexorValue,并希望使用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);
  );

如果只想在字段上执行几种类型的操作,那么将它们简单地包含在界面中是最简单的。另一方面,上面给出的方法允许接口以允许客户端对它们执行任意操作序列的方式公开其字段。