12

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

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

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

我面临两个问题:-

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

7 回答 7

29

为什么不在 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;
于 2012-05-04T11:12:06.957 回答
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;
于 2012-05-04T11:14:35.207 回答
3

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

于 2012-05-04T11:13:37.937 回答
2

接口可能包含属性,即:

public interface IFoo
{
    string Bar { get; set; }
}
于 2012-05-04T11:10:11.060 回答
2

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

遗产:

    var myCclass = 新的 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,接口在这里不合适。

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

于 2012-08-10T03:05:49.717 回答
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;
        }
    }
}
于 2012-05-04T11:18:32.043 回答
1

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

接口 ISomeProperties
  {int prop1 {get;set;}; 字符串 prop2 {get; 放;}}
接口 IMoreProperties
  {string prop3 {get;set;}; 双prop4 {get; 放;}}
接口 ICombinedProperties : ISomeProperties, IMoreProperties;
  { }

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

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

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

委托 void ActionByRef<T1>(ref T1 p1);
委托 void ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);
委托 void ActionByRef<T1,T2,T3>(ref T1 p1, ref T2 p2, ref T3 p3);
接口 IThing
{ // 必须允许客户端代码直接使用 T 类型的字段。
  void ActOnThing(ActionByRef<T> proc);
  void ActOnThing<ExtraT1>(ActionByRef<T, ExtraT1> proc, ref ExtraT1 ExtraP1);
  无效 ActOnThing<ExtraT1, ExtraT2>
       (ActionByRef<T> 过程,参考 ExtraT1 ExtraP1,参考 ExtraT2 ExtraP2);
}

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

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

或者,如果一个人有局部变量maskValue并且xorValue想用原子方式更新该字段field = (field & maskValue) ^ xorValue

  theInstance.ActOnThing(
    (ref int Param, ref int MaskValue, ref int XorValue) => {
        诠释旧值,新值;
        做 {oldValue = 参数; newValue = (oldValue & MaskValue) ^ XorValue;
        while (Threading.Interlocked.CompareExchange(ref Param, newValue, oldValue) !=
          旧值),
    参考掩码值,参考异或值);
  );

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

于 2012-08-06T15:38:44.863 回答