2010-02-11 25 views
5

Điều tôi muốn đạt được là: Tôi có thuộc tính được khai báo trong BaseClass. Nếu thuộc tính này được truy cập thông qua con trỏ của lớp cơ sở, chỉ có getter nên có sẵn nhưng nếu con trỏ lớp dẫn xuất được sử dụng, tôi muốn có thể nhận và thiết lập thuộc tính. Vì vậy, intellisense thậm chí không nên hiển thị một setter cho con trỏ cơ sở.Tạo một thuộc tính chỉ đọc có thể ghi trong lớp dẫn xuất

public class BaseClass 
{ 
    public virtual int MyProperty 
    { 
     get { return 1; } 
     set {;}//This would show the setter in Intellisense 
    } 
} 

public class DerivedClass : BaseClass 
{ 
    int intValue; 

    public override int MyProperty 
    { 
     set { intValue = value;} 
    } 
} 

Một ví dụ thực tế:
Hãy xem xét một tình huống mà bạn có một lớp mẹ và trẻ em có nguồn gốc từ lớp Person. Hãy tưởng tượng một thuộc tính -RestrictionLevel, nơi cả hai có thể đọc nó nhưng chỉ cha mẹ mới có thể đặt giá trị. Có cách nào tốt hơn để thiết kế tình huống này không?

+0

Liên kết chéo: http://stackoverflow.com/questions/1489361/override-abstract-readonly-property-to-read-write-property – Mikhail

+0

Chỉ cần thiết để ngăn chặn việc đọc chỉ đọc đối tượng đang được cập nhật gián tiếp . Cảm ơn bạn đã đặt câu hỏi trước khi tôi cần câu trả lời. –

Trả lời

0

Không thể (AFAIK). Dù sao thì cũng sẽ rất khó hiểu. Bất kỳ lý do cụ thể nào bạn muốn làm điều này?

+0

@ silky Vâng, tôi muốn tránh mã khách hàng thiết lập nó trên một con trỏ cơ sở nhưng chỉ trên con trỏ có nguồn gốc. Cung cấp một setter rỗng sẽ đạt được mục đích nhưng tôi muốn cung cấp một lỗi thời gian biên dịch nếu một nỗ lực được thực hiện để thiết lập nó trên con trỏ cơ sở – alwayslearning

+0

@alwayslearning: Tôi tự hỏi cấu trúc nào sẽ gợi ý một yêu cầu như vậy. Nó không có vẻ tự nhiên; nhưng tôi có thể nhầm. Bạn có thể xây dựng trên trường hợp chính xác bạn đang nói về? –

+0

đã cập nhật câu hỏi với trường hợp sử dụng – alwayslearning

9

Cách duy nhất tôi có thể nghĩ đến là bóng bất động sản với một hình mới:

public class DerivedClass : BaseClass 
{ 
    int intValue; 

    public new int MyProperty 
    { 
     get { return intValue; } 
     set { intValue = value; } 
    } 
} 

Thông báo như thế nào tài sản được khai báo new thay vì override. Điều này có nghĩa là, tất nhiên, MyProperty của loại DerivedClass không có gì để làm với MyProperty loại BaseClass, đó là một thuộc tính hoàn toàn mới có cùng tên (do đó ẩn một tên khỏi lớp cơ sở).

Kết quả là thế này:

DerivedClass d = new DerivedClass(); 
d.MyProperty = 42; 

BaseClass b = new DerivedClass(); 
b.MyProperty = 42; /* compilation error: Property or indexer 
              'TheNamespace.BaseClass.MyProperty' 
              cannot be assigned to -- it is 
              read only */ 

Ngoài ra, như bang @silky trong các bình luận:

(mặc dù tôi đề nghị bạn thực hiện nó, và phụ huynh, tham khảo các biến tương tự để tránh một tình huống rất khó hiểu) nhưng Tôi thực sự không nghĩ rằng điều này sẽ bao giờ là thích hợp.

... bạn có thể muốn có thuộc tính mới truy cập thuộc tính từ lớp cơ sở (thông qua base.MyProperty, hoàn tất bằng trình bảo vệ được thiết lập). Hãy xem xét những điều sau ví dụ:

DerivedClass d = new DerivedClass(); 
d.MyProperty = 42; 

BaseClass b = d; 
Console.WriteLine(b.MyProperty); // prints 1 

Điều đó nói rằng, tôi luôn luôn cảm thấy một chút bẩn khi sử dụng new (trong đó, khi tôi nghĩ về nó, tôi không chắc chắn rằng tôi đã thực sự thực hiện trong mã sản xuất).

Cập nhật
Với kịch bản ví dụ mà bạn đưa ra (mà tôi giải thích theo một cách mà một Parent là để có thể thiết lập các RestrictionLevel của một Child), nó có thể được giải quyết như thế này:

public enum RestrictionLevel 
{ 
    Low, 
    Medium, 
    Grounded 
} 

public class Person 
{ 
    public RestrictionLevel RestrictionLevel { get; private set; } 
    protected static void SetRestrictionLevelInternal(Person person, RestrictionLevel restrictionLevel) 
    { 
     person.RestrictionLevel = restrictionLevel; 
    } 
} 

public class Child : Person { } 

public class Parent : Person 
{ 
    public void SetRestrictionLevel(Child child, RestrictionLevel restrictionLevel) 
    { 
     SetRestrictionLevelInternal(child, restrictionLevel); 
    } 
} 

Điều này có nghĩa rằng đoạn mã sau là hợp lệ:

Child c = new Child(); 
Parent p = new Parent(); 
p.SetRestrictionLevel(c, RestrictionLevel.Grounded); 

...nhưng điều này không phải là:

Child c = new Child(); 
c.SetRestrictionLevel(c, RestrictionLevel.Low); 

Phương pháp SetRestrictionLevelInternal thể được gọi từ trong bất kỳ loại hậu duệ (bao gồm Child), nhưng không thể được gọi từ bên ngoài kiểu riêng của mình. Vì vậy, bạn không thể gọi SetRestrictionLevelInternal trên phiên bản Parent. Trong ví dụ trên, chúng tôi chọn hiển thị phương thức public, lần lượt gọi phương thức protected.

+0

Tôi sẽ upvote điều này để trở thành 'giải pháp' (mặc dù tôi đề nghị bạn thực hiện nó và phụ huynh, tham khảo cùng biến để tránh tình huống rất khó hiểu) nhưng tôi thực sự không nghĩ rằng điều này sẽ thích hợp. –

+0

@silky: điểm tốt; bao gồm chúng trong câu trả lời. –

+0

Câu trả lời hay, không phải thứ tôi từng trải qua –

4

Chương trình để một giao diện, không phải là một thực hiện:

public interface IFoo 
{ 
    int MyProp { get; } 
} 

public interface IFooWithSetter 
{ 
    int MyProp { get; set; } 
} 

public class FooImplementation : IFoo, IFooWithSetter 
{ 
    public int MyProp 
    { 
     get { return 100; } 
     set { } 
    } 
} 

mẫu Cách sử dụng:

IFoo var1 = new FooImplementation(); // only getter is available in var1 
IFooWithSetter var2 = (IFooWithSetter) var1; // setter and getter is available in var2 

Bạn có thể dễ dàng sử dụng một số từ bổ nghĩa riêng cho giao diện với các hợp đồng khác nhau. Giải pháp này là đơn giản và IMO đó là dãy phòng tốt cho nhiệm vụ của bạn.
Và nếu bạn nghĩ rằng sẽ dễ dàng thực hiện một số hành động bạn đang cố gắng ẩn/hạn chế, bạn đã đúng. Và tương tự với bất kỳ cách nào có thể là.

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