C# 中的接口与多重继承

本文关键字:多重继承 接口 | 更新日期: 2023-09-27 18:33:05

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

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

如何在 C# 中实现这一点?

我面临两个问题:-

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

C# 中的接口与多重继承

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

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";

查看文章组合与继承

编辑:

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

好吧,接口不能包含字段,如果您定义一个字段,则会出现编译错误。但是接口可以包含属性,但不能指定访问说明符,因为接口的所有元素都被视为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;

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

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;

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

接口可能包含属性,即:

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

请考虑在使用继承副组合时如何以不同的方式向客户端公开属性。

遗产:

   var myCclass = new Cclass;    myClass.propertyA;    myClass.propertyB;    myClass.propertyC;    等等

组成:

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

继承提供了一个更干净的 API - 一件好事。

作文要求我对班级的内部结构有所了解——这不是一件好事。这违反了得墨忒耳定律——更广为人知的是最小知识原则。你可以通过让Cclass属性一对一地公开/返回Bclass和Aclass属性来解决这个问题 - 然后你的Bclass & Aclass引用将是私有的或在Cclass中受到保护。Cclass可以完全控制暴露的内容,而不是依靠A&B来没有公开的东西。

我同意@AlejoBrz,接口在这里不合适。

我也赞同"更喜欢作曲而不是继承"。但这是一个指导方针,而不是一个硬性规定。

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

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

接口 ISome属性  {int prop1 {get;set;}; string prop2 {get; set;}}接口 IM更多属性  {string prop3 {get;set;}; double prop4 {get; set;}}接口 ICombinedProperties : ISomeProperties, IMoreProperties;  { }

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

但是,应该注意的是,有些事情可以用字段完成,而不能用属性完成。 例如,虽然字段可以传递给Interlocked.Increment但属性不能;尝试通过将属性复制到变量来Interlocked.Increment属性,调用Interlocked.Increment,然后将结果复制回属性在某些情况下可能"有效",但如果两个线程尝试同时执行相同的操作,则会失败(例如,两个线程都可以读取值 5, 将其递增到 6,然后写回 6,而让两个线程在最初等于 5 的字段上调用 Interlocked.Increment 可以保证产生 7。

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

delegate void ActionByRef(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(;界面 伊兴{//必须允许客户端代码直接处理 T 类型的字段。  void ActOnThing(ActionByRef proc(;  void ActOnThing(ActionByRef<T,> proc, ref ExtraT1 ExtraP1(;  void ActOnThing<ExtraT1,>       (ActionByRef 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;        而 (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue( !=          旧值(,    ref maskValue, ref xorValue(;  );

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