2012-05-04 44 views
12

Tôi có một nhóm lớp A và lớp B đều có một số thuộc tính. và một Class C khác có đặc tính riêng của họ.Giao diện với nhiều lần thừa kế trong C#

Bất cứ khi nào tôi tạo một thể hiện của lớp C tôi muốn truy cập tất cả các thuộc tính của cả ba lớp với objClassC.

Làm cách nào tôi có thể đạt được điều này trong C#?

tôi đang phải đối mặt với hai vấn đề: -

  1. tôi không thể thừa hưởng cả các lớp A, B trong Class C (C# không hỗ trợ nhiều Inheritance)
  2. nếu tôi sử dụng giao diện thay vì Class A , B (Trong giao diện chúng ta không thể có Fields)
+3

Bạn có thể sử dụng bố cục. Ngoài ra còn có [mixins] (http://stackoverflow.com/questions/255553/is-it-possible-to-implement-mixins-in-c) –

Trả lời

29

Tại sao bạn không chứa thể hiện của Class A và Class B bên trong lớp C. Sử dụng Composition

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

Sau đó, bạn có thể truy cập

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

kiểm tra bài viết của Composition vs Inheritance

EDIT:

nếu tôi sử dụng Giao diện inste quảng cáo của Class A, B (Trong giao diện chúng ta không thể Có Fields)

Vâng, giao diện không thể chứa các lĩnh vực, nếu bạn định nghĩa một, bạn sẽ nhận được lỗi biên dịch. Nhưng các giao diện có thể chứa các thuộc tính với ngoại lệ mà bạn không thể chỉ định access specifiers, vì tất cả các phần tử của giao diện được coi là public. Bạn có thể xác định các thuộc tính cho giao diện 'A' và 'B' như:

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


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

Sau đó, bạn có thể thực hiện chúng trong lớp C như:

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

Sau đó bạn có thể sử dụng chúng như:

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

+1 cho thành phần thừa kế –

+2

@downvoter, hãy chú ý – Habib

+0

Nhưng nếu thực hiện IA, IB là cần thiết trong lớp C thì cần phải thực hiện IA, và IB là gì? chúng ta chỉ có thể định nghĩa các thuộc tính mà không cần thực hiện các giao diện ...? –

2

Giao diện có thể chứa các thuộc tính, tức là .:

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

Giao diện không phải là giải pháp cho việc thiếu nhiều thừa kế. Họ không làm những điều tương tự. Gần nhất bạn có thể nhận được là tạo C là một phân lớp của A và có thuộc tính loại B. Có lẽ nếu bạn cho chúng tôi biết A, B và C nên làm gì, chúng tôi có thể đưa ra câu trả lời phù hợp hơn với nhu cầu của bạn ...

4

Giao diện có thể có các thuộc tính nhưng nếu bạn cũng muốn sử dụng các phương pháp thì bố cục chế phẩm hoặc phụ thuộc có thể được yêu cầu.

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


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

class C : A, B 
{ 

} 

// đặt những tuyên bố trong một số phương pháp

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

Giao diện không thể chứa các lĩnh vực, nhưng chúng có thể chứa các thuộc tính. Trong hầu hết các trường hợp, thuộc tính có thể được sử dụng như các lĩnh vực, và không có khó khăn với câu nói:

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

Cho một vị trí lưu trữ của loại ICombinedProperties, người ta có thể truy cập tất cả bốn thuộc tính trực tiếp và không ồn ào.

Tuy nhiên, cần lưu ý rằng có một vài điều có thể được thực hiện với các trường không thể thực hiện với các thuộc tính. Ví dụ: trong khi một trường có thể được chuyển đến Interlocked.Increment thì một thuộc tính không thể; cố gắng để Interlocked.Increment một thuộc tính bằng cách sao chép nó vào một biến, gọi Interlocked.Increment trên đó và sau đó sao chép kết quả trở lại thuộc tính có thể "hoạt động" trong một số trường hợp, nhưng sẽ thất bại nếu hai chủ đề cố gắng thực hiện cùng một điều có thể ví dụ cho cả hai chủ đề để đọc một giá trị 5, tăng nó lên 6, và sau đó viết lại 6, trong khi có hai chủ đề gọi Interlocked.Increment trên một trường ban đầu bằng 5 sẽ được đảm bảo mang lại 7.).

Để giải quyết vấn đề này, có thể cần có một số phương pháp thực hiện một phương thức liên khóa trên một trường (ví dụ: có thể có hàm gọi Interlocked.Increment trên trường và trả về kết quả) và/hoặc bao gồm các chức năng mà sẽ gọi một đại biểu chỉ định với một lĩnh vực như một tham số ref (ví dụ

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

với một thể hiện của giao diện, người ta có thể làm điều gì đó như:

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

hay, nếu ai có biến cục bộ maskValuexorValue và muốn atomically cập nhật các trường với 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); 
); 

Nếu chỉ có một vài loại hành động người ta sẽ muốn thực hiện trên các lĩnh vực, nó sẽ là đơn giản nhất để đơn giản bao gồm chúng trong giao diện. Mặt khác, cách tiếp cận được đưa ra ở trên cho phép một giao diện để lộ các trường của nó theo cách sao cho cho phép các máy khách thực hiện các chuỗi hành động tùy ý trên chúng.

+0

-1. không giải quyết câu hỏi. – radarbob

+0

@radarbob: Một phần của câu hỏi phải làm với thực tế là các giao diện không thể chứa các trường. Các câu trả lời khác thừa nhận rằng trong nhiều trường hợp, người ta có thể sử dụng các thuộc tính thay vì các trường. Tôi muốn khuếch đại một thực tế là nó có thể sử dụng giao diện ngay cả khi người ta muốn sử dụng các lĩnh vực theo cách mà tài sản không phải là một thay thế chấp nhận được. – supercat

1

Xem xét cách các thuộc tính được hiển thị khác nhau cho ứng dụng khách khi sử dụng thành phần phó kế thừa.

Inheritance:

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

Thành phần:

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

thừa kế cho một API sạch hơn - một điều tốt.

Thành phần yêu cầu tôi biết điều gì đó về cấu trúc bên trong của lớp - không phải là điều tốt. Điều này vi phạm các law of demeter - tốt hơn được gọi là nguyên tắc của kiến ​​thức ít nhất.Bạn có thể giải quyết vấn đề này bằng cách có các thuộc tính Cclass mà một đối một phơi bày/trả về lớp Bclass & Các thuộc tính Aclass - và lớp Bclass & Các tham chiếu Aclass của bạn sẽ được riêng tư hoặc được bảo vệ trong lớp Cclass. VÀ Cclass có toàn quyền kiểm soát những gì được phơi bày thay vì phụ thuộc vào A & B để không có công cụ công cộng mà bạn không bị phơi nhiễm.

Tôi đồng ý với @AlejoBrz, giao diện không phù hợp tại đây.

Tôi cũng gật đầu để "thích thành phần hơn thừa kế". Nhưng đây là một hướng dẫn, không phải là một quy tắc cứng nhắc và nhanh chóng.

Các vấn đề liên quan