每当我创建Class C的实例,我都想用objClassC访问所有三个类的属性。
如何在C#中实现这一点?
我面临两个问题:
1.我不能在Class C中继承Class A,B(C#不支持多重继承); 2.如果我使用接口代替Class A,B(在接口中我们不能包含字段)。
为什么不把A类和B类的实例放在C类中呢?可以使用组合
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;
C
或任何实现接口IA
和IB
的其他类的对象,并具有多态行为。上面的代码只是一个例子,我还没有遇到过接口只有一堆属性而没有方法的真实场景。 - Habib接口可以具有属性,但如果您还想使用方法,则可能需要组合或依赖注入。
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;
myCclass.bClass.propertyB;
myCclass.aClass.propertyA;
myCclass.propertyC;
组合要求我了解类的内部结构 - 这并不是一件好事。这违反了德米特法则,也被称为最小知识原则。你可以通过在C类中拥有与B类和A类属性一一对应的属性来避免这种情况 - 并且你的B类和A类引用将在C类中是私有或受保护的。而C类完全控制着暴露的内容,而不是依赖于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;
}
}
}
接口不能包含字段,但它们可以包含属性。在大多数情况下,属性可以像字段一样使用,并且没有难度:
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
,然后将结果再次复制回属性来“增加”属性,在某些情况下可能会“成功”,但如果两个线程同时尝试做同样的事情,则会失败(例如,两个线程都可以读取值为5的值,将其增加到6,然后写回6,而两个线程调用最初等于5的字段上的Interlocked.Increment
将保证产生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 { // 必须允许客户端代码直接使用类型为 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) );
或者,如果有本地变量 maskValue
和 xorValue
,并且想要原子更新字段为 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); );
如果只有少数几种类型的操作需要对字段执行,最简单的方法是将它们直接包含在接口中。另一方面,上述方法允许接口以这样的方式公开其字段,以使客户端可以对其执行任意序列的操作。