2009-09-28 49 views
19

Tôi muốn chỉ thực thi việc khởi động C# trên một thuộc tính đã cho từ một lớp trừu tượng cơ bản. Các lớp có nguồn gốc có thể, nếu họ muốn, cũng cung cấp một setter cho tài sản đó cho việc sử dụng công khai của kiểu ràng buộc tĩnh.Ghi đè thuộc tính chỉ đọc trừu tượng để đọc/ghi thuộc tính

Với lớp trừu tượng sau:

public abstract class Base 
{ 
    public abstract int Property { get; } 
} 

Nếu tôi muốn có một lớp được thừa kế mà còn thực hiện một setter, tôi ngây thơ có thể thử:

public class Derived : Base 
{ 
    public override int Property 
    { 
     get { return field; } 
     set { field = value; } // Error : Nothing to override. 
    } 

    private int field; 
} 

Nhưng sau đó tôi nhận được một lỗi cú pháp kể từ khi tôi cố gắng ghi đè lên setter không tồn tại. Tôi đã thử một số cách khác như tuyên bố setter cơ sở tư nhân và như vậy và tôi vẫn vấp ngã khi tất cả các loại lỗi ngăn cản tôi làm điều đó. Phải có một cách để làm điều đó vì nó không phá vỡ bất kỳ hợp đồng lớp cơ sở nào.

Thật không may, nó có thể được thực hiện với giao diện, nhưng tôi thực sự cần thực hiện mặc định đó.

Tôi tình cờ gặp tình huống đó thường xuyên, tôi tự hỏi liệu có một mẹo cú pháp C# ẩn để làm điều đó không, tôi sẽ chỉ sống với nó và thực hiện phương thức SetProperty() thủ công.

+0

Cross-link: http://stackoverflow.com/questions/2243886/make-a-read-only-property-writable-in-the-derived-class – Mikhail

Trả lời

11

Bạn không thể thực hiện trực tiếp vì bạn không thể newoverride có cùng chữ ký trên cùng một loại; có hai tùy chọn - nếu bạn kiểm soát các lớp cơ sở, thêm một tài sản thứ hai:

public abstract class Base 
{ 
    public int Property { get { return PropertyImpl; } } 
    protected abstract int PropertyImpl {get;} 
} 
public class Derived : Base 
{ 
    public new int Property {get;set;} 
    protected override int PropertyImpl 
    { 
     get { return Property; } 
    } 
} 

khác bạn có thể giới thiệu một cấp thêm trong hệ thống phân cấp lớp:

public abstract class Base 
{ 
    public abstract int Property { get; } 
} 
public abstract class SecondBase : Base 
{ 
    public sealed override int Property 
    { 
     get { return PropertyImpl; } 
    } 
    protected abstract int PropertyImpl { get; } 
} 
public class Derived : SecondBase 
{ 
    public new int Property { get; set; } 

    protected override int PropertyImpl 
    { 
     get { return Property; } 
    } 
} 
+0

giải pháp của bạn là thú vị, tôi sẽ suy nghĩ một chút về chúng. – Coincoin

+1

Giải pháp của bạn là điều gần nhất với điều này. Nhưng tôi không nghĩ rằng nó có thể làm điều đó mà không ép buộc lớp dẫn xuất làm nhào lộn. – Coincoin

2

gì về cái gì đó như:

public abstract class Base 
{ 
    public virtual int Property 
    { 
     get { return this.GetProperty(); } 
     set { } 
    } 

    protected abstract int GetProperty(); 
} 
+1

Bất kỳ người thừa kế nào cũng phải ghi đè cả hai người thừa kế - một chút dư thừa? –

+0

Chỉ khi ghi đè tài sản. Khác, mà không có tài sản ảo mà thực sự có thể là một lựa chọn thay thế có thể chấp nhận được. – Coincoin

+1

Nếu bạn không ghi đè thuộc tính, mục đích của bộ này rất ... bất thường. –

1

Điều này có phù hợp với nhu cầu của bạn không?

public abstract class TheBase 
{ 
    public int Value 
    { 
     get; 
     protected set; 
    } 
} 
public class TheDerived : TheBase 
{ 
    public new int Value 
    { 
     get { return base.Value; } 
     set { base.Value = value; } 
    } 
} 

virtual bị xóa, nhưng giá trị cơ sở vẫn là giá trị duy nhất cho giá trị. Vì vậy, điều này sẽ hiển thị '5'. Và trình biên dịch nên phiền phức về b.Value = 4;

TheDerived d = new TheDerived(); 
d.Value = 5; 
TheBase b = d; 
//b.Value = 4; // uncomment for compiler error 
cout << "b.Value == " << b.Value << endl; 

-Jesse

1

Tôi đã có một yêu cầu tương tự như nơi tôi cần một giao diện để có thể chia sẻ chức năng sắp xếp chung giữa hai lớp lỏng lẻo liên quan. Một người trong số họ có một tài sản Đặt hàng chỉ đọc và người kia có một tài sản Đặt hàng đọc-ghi, nhưng tôi cần một cách để đọc tài sản theo cùng một cách từ cả hai lớp.

Nó chỉ ra rằng điều này có thể được thực hiện bằng cách ẩn giá trị chỉ đọc trong một giao diện có nguồn gốc. Đây là cách tôi đã làm nó.

interface ISortable 
{ 
    int Order { get; } 
} 

interface ISortableClass2 
    : ISortable 
{ 
    // This hides the read-only member of ISortable but still satisfies the contract 
    new int Order { get; set; } 
} 

class SortableClass1 
    : ISortable 
{ 
    private readonly int order; 

    public SortableClass1(int order) 
    { 
     this.order = order; 
    } 

    #region ISortable Members 

    public int Order 
    { 
     get { return this.order; } 
    } 

    #endregion 
} 

class SortableClass2 
    : ISortableClass2 
{ 
    #region ISortableClass2 Members 

     public int Order { get; set; } 

    #endregion 
} 

class RunSorting 
{ 
    public static void Run() 
    { 
     // Test SortableClass1 
     var list1 = new List<SortableClass1>(); 

     list1.Add(new SortableClass1(6)); 
     list1.Add(new SortableClass1(1)); 
     list1.Add(new SortableClass1(5)); 
     list1.Add(new SortableClass1(2)); 
     list1.Add(new SortableClass1(4)); 
     list1.Add(new SortableClass1(3)); 

     var sorted1 = SortObjects(list1); 

     foreach (var item in sorted1) 
     { 
      Console.WriteLine("SortableClass1 order " + item.Order); 
     } 

     // Test SortableClass2 
     var list2 = new List<SortableClass2>(); 

     list2.Add(new SortableClass2() { Order = 6 }); 
     list2.Add(new SortableClass2() { Order = 2 }); 
     list2.Add(new SortableClass2() { Order = 5 }); 
     list2.Add(new SortableClass2() { Order = 1 }); 
     list2.Add(new SortableClass2() { Order = 4 }); 
     list2.Add(new SortableClass2() { Order = 3 }); 

     var sorted2 = SortObjects(list2); 

     foreach (var item in sorted2) 
     { 
      Console.WriteLine("SortableClass2 order " + item.Order); 
     } 
    } 

    private static IEnumerable<T> SortObjects<T>(IList<T> objectsToSort) where T : ISortable 
    { 
     if (objectsToSort.Any(x => x.Order != 0)) 
     { 
      return objectsToSort.OrderBy(x => x.Order); 
     } 

     return objectsToSort; 
    } 
} 
Các vấn đề liên quan