2008-08-04 44 views
33

Tôi đang tìm cách nào đó để ẩn các thành viên được kế thừa một cách hiệu quả. Tôi có một thư viện các lớp học được thừa kế từ các lớp cơ sở chung. Một số lớp hậu duệ mới hơn kế thừa các thuộc tính phụ thuộc đã trở thành kháng cáo và có thể hơi khó hiểu khi sử dụng IntelliSense hoặc sử dụng các lớp trong trình thiết kế trực quan.Ẩn các thành viên được thừa kế

Các lớp này là tất cả các điều khiển được viết để được biên dịch cho WPF hoặc Silverlight 2.0. Tôi biết về ICustomTypeDescriptorICustomPropertyProvider, nhưng tôi khá chắc chắn những người không thể sử dụng trong Silverlight.

Nó không phải là một vấn đề chức năng như là một vấn đề khả năng sử dụng. Tôi nên làm gì?

Cập nhật

Một số các thuộc tính mà tôi thực sự muốn ẩn đến từ tổ tiên mà không phải là của riêng tôi và vì một công cụ cụ thể Tôi đang thiết kế cho, tôi không thể làm thành viên ẩn với nhà điều hành new. (Tôi biết, thật nực cười)

Trả lời

32

Override họ như Michael Gợi ý above và để ngăn chặn folks từ bằng cách sử dụng ghi đè phương pháp , đánh dấu chúng là lỗi thời:

[Obsolete("These are not supported in this class.", true)] 
public override void dontcallmeanymore() 
{ 
} 

Nếu parm thứ hai được đặt thành true, lỗi trình biên dịch sẽ được tạo nếu có ai cố gắng gọi phương thức đó và chuỗi trong parm đầu tiên là thông báo.Nếu parm2 là false chỉ một cảnh báo trình biên dịch sẽ được tạo ra.

+0

Bạn không thể đóng dấu nó, cũng có cùng tác dụng không? –

+0

@JamesM không có obselete với thành viên ngăn chặn đúng _access_, niêm phong ngăn chặn thành viên _inheritance_. Vì vậy, một lớp niêm phong không thể được bắt nguồn từ, và một phương pháp niêm phong cho phép các thành viên lớp khác được ghi đè nhưng ngăn cản thành viên đó bị ghi đè. Sealed không ngăn chặn gọi lớp đó hoặc thành viên, trong khi obselete với đúng ném một lỗi trình biên dịch nếu bạn cố gắng gọi nó. –

+0

@RobertPetz khi sử dụng lỗi thời, nó đưa ra cảnh báo chứ không phải lỗi. Sự khác biệt lớn. –

16

Trong khi bạn không thể ngăn chặn việc sử dụng của những thành viên được thừa hưởng đến kiến ​​thức của tôi, bạn sẽ có thể để ẩn chúng từ IntelliSense sử dụng EditorBrowsableAttribute:

Using System.ComponentModel; 

[EditorBrowsable(EditorBrowsableState.Never)] 
private string MyHiddenString = "Muahahahahahahahaha"; 

Edit: Chỉ cần thấy điều này trong các nhận xét về tài liệu, điều này làm cho nó vô dụng vì mục đích này:

Có một lưu ý nổi bật cho biết thuộc tính này "không chặn các thành viên trong một lớp trong cùng một cụm". Điều đó đúng nhưng không hoàn chỉnh. Trên thực tế, thuộc tính không ngăn chặn các thành viên từ một lớp trong cùng một giải pháp.

8

Tôi nghĩ rằng bạn tốt nhất là cách hackish nhất là xem xét bố cục trái ngược với thừa kế.

Hoặc, bạn có thể tạo giao diện có các thành viên bạn muốn, nhờ lớp dẫn xuất của bạn triển khai giao diện đó và chương trình chống lại giao diện.

13

Một điều bạn có thể làm là chứa đối tượng thay vì mở rộng từ lớp khác. Điều này sẽ cung cấp cho bạn sự linh hoạt nhất trong việc phơi bày những gì bạn muốn phơi bày, nhưng nếu bạn hoàn toàn cần đối tượng để thuộc loại đó thì đó không phải là giải pháp lý tưởng (tuy nhiên bạn có thể phơi bày vật thể từ bộ thu).

Như vậy:

public class MyClass : BaseClass 
{ 
    // Your stuff here 
} 

trở thành:

public class MyClass 
{ 
    private BaseClass baseClass; 

    public void ExposeThisMethod() 
    { 
     baseClass.ExposeThisMethod(); 
    } 
} 

Hoặc: (? Sp)

public class MyClass 
{ 
    private BaseClass baseClass; 

    public BaseClass BaseClass 
    { 
     get 
     { 
      return baseClass; 
     } 
    } 
} 
3

Tôi biết đã có một số câu trả lời cho điều này, và nó khá cũ, nhưng phương pháp đơn giản nhất để làm điều này chỉ là khai báo chúng là new private.

Hãy xem xét ví dụ mà tôi hiện đang làm việc, nơi tôi có API cung cấp mọi phương thức trong DLL của bên thứ ba. Tôi phải dùng các phương thức của chúng, nhưng tôi muốn sử dụng một thuộc tính .Net, thay vì phương thức "getThisValue" và "setThisValue". Vì vậy, tôi xây dựng một lớp thứ hai, kế thừa đầu tiên, tạo một thuộc tính sử dụng các phương thức get và set, và sau đó ghi đè lên các phương thức get và set ban đầu là riêng tư. Chúng vẫn có sẵn cho bất kỳ ai muốn xây dựng thứ gì đó khác biệt trên chúng, nhưng nếu chúng chỉ muốn sử dụng động cơ tôi đang xây dựng, thì chúng sẽ có thể sử dụng các đặc tính thay vì các phương pháp.

Sử dụng phương pháp lớp kép sẽ loại bỏ mọi hạn chế khi không thể sử dụng tuyên bố new để ẩn thành viên. Bạn chỉ đơn giản là không thể sử dụng override nếu các thành viên được đánh dấu là ảo.

public class APIClass 
{ 
    private static const string DllName = "external.dll"; 

    [DllImport(DllName)] 
    public extern unsafe uint external_setSomething(int x, uint y); 

    [DllImport(DllName)] 
    public extern unsafe uint external_getSomething(int x, uint* y); 

    public enum valueEnum 
    { 
     On = 0x01000000; 
     Off = 0x00000000; 
     OnWithOptions = 0x01010000; 
     OffWithOptions = 0x00010000; 
    } 
} 

public class APIUsageClass : APIClass 
{ 
    public int Identifier; 
    private APIClass m_internalInstance = new APIClass(); 

    public valueEnum Something 
    { 
     get 
     { 
      unsafe 
      { 
       valueEnum y; 
       fixed (valueEnum* yPtr = &y) 
       { 
        m_internalInstance.external_getSomething(Identifier, yPtr); 
       } 
       return y; 
      } 
     } 
     set 
     { 
      m_internalInstance.external_setSomething(Identifier, value); 
     } 
    } 

    new private uint external_setSomething(int x, float y) { return 0; } 
    new private unsafe uint external_getSomething(int x, float* y) { return 0; } 
} 

Giá trị hiện tạiEnum khả dụng cho cả hai lớp, nhưng chỉ có thuộc tính hiển thị trong lớp APIUsageClass. Lớp APIClass vẫn có sẵn cho những người muốn mở rộng API ban đầu hoặc sử dụng nó theo một cách khác, và APIUsageClass có sẵn cho những người muốn một cái gì đó đơn giản hơn.

Cuối cùng, những gì tôi sẽ làm là làm cho nội bộ của APIClass và chỉ hiển thị lớp được kế thừa của tôi.

+0

Làm thế nào để sử dụng điều này cho các thuộc tính phụ thuộc? –

1

Tôi đã thử nghiệm tất cả các giải pháp được đề xuất và họ không thực sự ẩn thành viên mới.

Nhưng có một điều này:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
public new string MyHiddenProperty 
{ 
    get { return _myHiddenProperty; } 
} 

Nhưng trong mã behide nó vẫn còn truy cập, vì vậy thêm thuộc tính cũng như cũ

[Obsolete("This property is not supported in this class", true)] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
public new string MyHiddenProperty 
{ 
    get { return _myHiddenProperty; } 
} 
3

Để ẩn hoàn toàn và đánh dấu không sử dụng, bao gồm IntelliSense mà Tôi tin là điều mà hầu hết người đọc mong đợi ...

[Obsolete("Not applicable in this class.")] 
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
0

Bạn có thể sử dụng giao diện

public static void Main() 
    { 
     NoRemoveList<string> testList = ListFactory<string>.NewList(); 

     testList.Add(" this is ok "); 

     // not ok 
     //testList.RemoveAt(0); 
    } 

    public interface NoRemoveList<T> 
    { 
     T this[int index] { get; } 
     int Count { get; } 
     void Add(T item); 
    } 

    public class ListFactory<T> 
    { 
     private class HiddenList: List<T>, NoRemoveList<T> 
     { 
      // no access outside 
     } 

     public static NoRemoveList<T> NewList() 
     { 
      return new HiddenList(); 
     } 
    } 
Các vấn đề liên quan