2012-02-20 43 views
5

爲什麼,下面是合法的C#:添加訪問接口屬性允許的,但不是抽象屬性

public interface ISomeInterface 
{ 
    int SomeProperty 
    { 
     get; 
    } 
} 

public class SomeClassImplementingInterface : ISomeInterface 
{ 
    public int SomeProperty 
    { 
     get { return 32; } 
     protected set {} 
    } 
} 

但這不是:

public abstract class SomeAbstractClass 
{ 
    public abstract int SomeProperty 
    { 
     get; 
    } 
} 

public class SomeClassExtendingAbstractClass : SomeAbstractClass 
{ 
    public override int SomeProperty 
    { 
     get { return 32; } 
     protected set {} 
    } 
} 

在以下後者結果編譯時錯誤:

'InterfaceAbstractTest.SomeClassExtendingAbstractClass.SomeProperty.set': cannot override because 'InterfaceAbstractTest.SomeAbstractClass.SomeProperty' does not have an overridable set accessor InterfaceAbstractTest

在允許前者的同時不禁止後者的原因是什麼?

+0

我認爲他們在這裏的話是「覆蓋」。沒有設置的方法來覆蓋。 – 2012-02-20 17:00:30

+0

或者,是否在屬性級別而不是訪問者級別指定了override關鍵字?畢竟,每個訪問者在涉及它時都是一個獨特的方法。 – 2012-02-20 17:02:40

+1

右鍵 - 抽象關鍵字在屬性級別,而不是訪問者級別。 – 2012-02-20 17:04:51

回答

3

因爲使用接口調用者只關心該接口至少的實施者實現了接口的定義,@davisoa狀態,而在你的例子SomeAbstractClass定義其中規定公共合同完全型,交通方便,和(用於屬性)成員的可讀性/可寫性。

如果使用反射來獲取SomeProperty的PropertyInfo(來自基類或子類),它需要從某處解析該信息。允許子類更改可讀性/可寫性與返回類型或參數列表中的更改一樣,會違反合同規定。

試想例如:

SomeAbstractClass sc = new SomeClassExtendingAbstractClass(); 
PropertyInfo pi = sc.GetType().GetProperty("SomeProperty"); 
Console.Out.WriteLine(pi.CanWrite); // What should be printed here? 
2

這是因爲該接口實現正在作出承諾,將會有一個屬性SomeProperty,你可以「搞定」。

抽象類實現承諾它的子類將使用公共get方法提供屬性SomeProperty的實現。

在結束時,將基類定義的東西必須重寫,而所述接口被限定合同一個

+0

就我而言,'SomeClassExtendingAbstractClass' * *提供了一個帶有公共get方法的'SomeProperty'屬性。對抽象接口工作的人來說,這也是無足輕重的。因此,我的問題。想象一下,如果每個get/set都是方法的話。想象一下,僅僅因爲你擴展了一個具有'GetValue'方法的抽象類,就無法提供'SetValue'方法。 – 2012-02-20 17:05:10

+2

@KentBoogaart就是這樣的事情 - 他們不只是獲得者和制定者。屬性是.NET中的一等公民,並且具有關於與該屬性相關的可讀性/可寫性的契約元數據。 – 2012-02-20 17:07:27

1

您試圖覆蓋不存在的集合運算符。要麼在抽象類中定義屬性的集合部分,要麼不要在具體類中定義一個屬性。既然你把這個集合作爲具體類中的保護對象,我的猜測是你想要做的是在抽象定義中創建一個受保護的集合運算符。

0

所需要的是既覆蓋現有的財產,並用新的陰影成可讀寫之一。不幸的是.net沒有提供任何覆蓋和遮蔽單個類中的成員的手段。最好的做法可能是讓抽象基類定義一個具體的非虛擬只讀屬性,它的getter調用一個抽象函數。然後,派生類可以使用非虛擬讀寫函數來映射該屬性,該函數在其getter中調用相同的函數,並在其setter中創建一個新的抽象函數或虛函數。

1

這是設計。我從C#語言規格報價:

An overriding property declaration must specify the exact same accessibility modifiers, types and name as the inherited property, if the inherited property has only a single accessor (i.e.,... ready only or write-only), the overriding property must include only that accessor.

是decesion背後的原因可能是因爲接口更加靈活的合同不是抽象類的類型。接口只關心最不共同的部分,而不是整個實現。我認爲有充分的理由選擇另一種設計。