2011-01-10 33 views
37

Tôi đang cố gắng tạo một lớp trừu tượng định nghĩa một thuộc tính với một trình khởi động. Tôi muốn để nó lên đến các lớp học có nguồn gốc để quyết định xem họ muốn thực hiện một setter cho tài sản hay không. Điều này có thể không?Thuộc tính trừu tượng với bộ thu công khai, xác định thiết lập riêng trong lớp bê tông có thể?

Những gì tôi có cho đến nay:

public abstract class AbstractClass { 
    public abstract string Value { get; } 
    public void DoSomething() { 
     Console.WriteLine(Value); 
    } 
} 

public class ConcreteClass1 : AbstractClass { 
    public override string Value { get; set; } 
} 

public class ConcreteClass2 : AbstractClass { 
    private string _value; 
    public override string Value { 
     get { return _value; } 
    } 
    public string Value { 
     set { _value = value; } 
    } 
} 

public class ConcreteClass3 : AbstractClass { 
    private string _value; 
    public override string Value { 
     get { return _value; } 
    } 
    public void set_Value(string value) { 
     _value = value; 
    } 
} 

Trong ConcreteClass1, tôi nhận được một lỗi trên set. Nó không thể ghi đè lên set_Value vì không có bộ truy cập có thể ghi đè có sẵn trong AbstractClass.

Trong ConcreteClass2, tôi gặp lỗi trên cả hai Value vì một thành viên có cùng tên đã được khai báo.

ConcreteClass3 không đưa ra lỗi, nhưng ngay cả khi bộ truy cập được đặt của Value sẽ được biên dịch thành set_Value, nó không hoạt động theo cách khác. Xác định set_Value không có nghĩa là Value sẽ có bộ truy cập được đặt. Vì vậy, tôi không thể gán một giá trị cho một thuộc tính ConcreteClass3.Value. Tôi có thể sử dụng ConcreteClass3.set_Value ("giá trị"), nhưng đó không phải là những gì tôi đang cố gắng đạt được ở đây.

Có thể có lớp trừu tượng yêu cầu trình thu thập dữ liệu công khai, trong khi cho phép thiết lập tùy chọn được định nghĩa trong lớp dẫn xuất không?

Trong trường hợp bạn tự hỏi, đây chỉ là một câu hỏi lý thuyết. Tôi không có một tình huống thực sự mà một cái gì đó như thế này là cần thiết. Nhưng tôi có thể tưởng tượng một lớp trừu tượng không quan tâm đến việc một thuộc tính được thiết lập như thế nào, nhưng điều đó cần phải có khả năng nhận được thuộc tính.

Trả lời

28

Thật không may, bạn không thể thực hiện chính xác những gì bạn muốn. Bạn có thể làm điều này với giao diện mặc dù:

public interface IInterface { 
    string MyProperty { get; } 
} 

public class Class : IInterface { 
    public string MyProperty { get; set; } 
} 

Con đường tôi sẽ làm điều đó là để có một phương pháp setProperty riêng biệt trong các lớp bê tông:

public abstract class AbstractClass { 
    public abstract string Value { get; } 
} 

public class ConcreteClass : AbstractClass { 

    private string m_Value; 
    public override string Value { 
     get { return m_Value; } 
    } 

    public void SetValue(string value) { 
     m_Value = value; 
    } 
} 
+0

Sử dụng 'giao diện', tôi không thể triển khai phương thức' DoSomething' trong lớp cơ sở của mình (không có lớp cơ sở, chỉ là một giao diện). Sử dụng 'SetValue' giống với' set_Value' trong 'ConcreteClass3' của tôi. Nhưng nếu đó là cách để đi, đặt tên nó là 'SetValue' có lẽ tốt hơn' set_Value'. – comecme

+0

Lý do set_Value không được liên kết với thuộc tính là có định nghĩa 'PropertyDef' rõ ràng trong hội đồng liên kết các phương thức' get_' và 'set_'; chỉ cần đặt tên một phương thức 'set_' không liên kết nó với thuộc tính. Không có cách nào để làm chính xác những gì bạn muốn trong C#; bạn sẽ phải thỏa hiệp. – thecoop

+0

Bạn có thể thực hiện 'DoSomething' làm phương thức mở rộng trên' IInterface'. Xem chỉnh sửa của tôi. – piedar

0

Không rất thanh lịch, nhưng đó là gần nhất bạn có thể có được mà không làm một cái gì đó giống như bạn có trong concreteclass3

public class Concrete : AbstractClass 
{ 
    public new void DoSomething() 
    { 
     Console.WriteLine(Value); 
    } 
} 

public abstract class AbstractClass 
{ 
    protected AbstractClass() 
    { 
     try 
     { 
      var value = Value; 
     } 
     catch (NotImplementedException) 
     { 
      throw new Exception("Value's getter must be overriden in base class"); 
     } 
    } 
    public void DoSomething() 
    { 
     Console.WriteLine(Value); 
    } 

    /// <summary> 
    /// Must be override in subclass 
    /// </summary> 
    public string Value { get { throw new NotImplementedException(); } } 
} 
+0

Tôi không hiểu tại sao bạn định nghĩa một 'DoSomething' mới trong lớp bê tông. Ngoài ra, giải pháp you'r sẽ ném một ngoại lệ vào thời gian chạy, tại thời gian biên dịch sự vắng mặt của việc thực hiện Giá trị sẽ không được chú ý. – comecme

5

Tìm thấy một giải pháp: How to override a getter-only property with a setter in C#?

public abstract class A 
{ 
    public abstract int X { get; } 
} 
public class B : A 
{ 
    public override int X { get { return 0; } } 
} 
/*public class C : B //won't compile: can't override with setter 
{ 
    private int _x; 
    public override int X { get { return _x; } set { _x = value; } } 
}*/ 
public abstract class C : B //abstract intermediate layer 
{ 
    public sealed override int X { get { return this.XGetter; } } 
    protected abstract int XGetter { get; } 
} 
public class D : C //does same thing, but will compile 
{ 
    private int _x; 
    protected sealed override int XGetter { get { return this.X; } } 
    public new virtual int X { get { return this._x; } set { this._x = value; } } 
} 

D giờ đây tương đương với một lớp kế thừa từ B trong khi cũng có thể ghi đè trong trình cài đặt.

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