2010-07-07 6 views
6

Ich verwende MS-Code-Verträge und habe einen Haken mit der Verwendung der Schnittstellenvererbung und der ContractClassFor-Attribute.Code Contracts: Umgang mit geerbten Schnittstellen?

diese Schnittstellen und Vertragsklassen Gegeben:

[ContractClass(typeof(IOneContract))] 
interface IOne { } 
[ContractClass(typeof(ITwoContract))] 
interface ITwo : IOne { } 

[ContractClassFor(typeof(IOne))] 
abstract class IOneContract : IOne { } 
[ContractClassFor(typeof(ITwo))] 
abstract class ITwoContract : IOneContract, ITwo { } 

Lassen Sie uns sagen, dass Ione und iTWO sind wesentliche Schnittstellen. So würde IOneContract eine erhebliche Menge an Code für die notwendigen Prüfungen enthalten.

Ich möchte das alles nicht in ITwoContract für die IOne-Schnittstellen duplizieren. Ich möchte nur neue Verträge für die ITwo-Schnittstellen hinzufügen. Das Erben einer Vertragsklasse von einer anderen scheint der wahrscheinliche Weg zu sein, diesen Code wiederzuverwenden. Aber ich bekomme den folgenden Fehler:

Ist dies eine Einschränkung in Code Contracts oder mache ich es falsch? Wir haben in unserem Projekt eine große Anzahl an Schnittstellen geerbt, was sich wie ein Deal Breaker für Code Contracts auswirkt, wenn ich nicht herausfinden kann, wie ich dieses Problem umgehen kann.

Antwort

10

Statt:

[ContractClassFor(typeof(ITwo))] 
abstract class ITwoContract : IOneContract, ITwo { } 

erben einfach den Vertrag:

[ContractClassFor(typeof(ITwo))] 
abstract class ITwoContract : ITwo { } 

Sie brauchen nur Verträge über die Methoden zu schaffen, die in ITwo neu sind. Die Verträge von IOneContract werden automatisch übernommen werden, und Sie können als abstrakte — in der Tat alle vererbten IOne Methoden erklären, Sie nicht Verträge für IOne auf ITwoContract liefern, oder CC wird sich beschweren :)

Zum Beispiel, wenn Sie haben dies:

[ContractClass(typeof (IOneContract))] 
interface IOne 
{ 
    int Thing { get; } 
} 

[ContractClass(typeof (ITwoContract))] 
interface ITwo : IOne 
{ 
    int Thing2 { get; } 
} 

[ContractClassFor(typeof (IOne))] 
abstract class IOneContract : IOne 
{ 
    public int Thing 
    { 
     get 
     { 
      Contract.Ensures(Contract.Result<int>() > 0); 
      return 0; 
     } 
    } 
} 

[ContractClassFor(typeof (ITwo))] 
abstract class ITwoContract : ITwo 
{ 
    public int Thing2 
    { 
     get 
     { 
      Contract.Ensures(Contract.Result<int>() > 0); 
      return 0; 
     } 
    } 

    public abstract int Thing { get; } 
} 

Dann wird diese Umsetzung "unbewiesen Vertrag", sagen beide Methoden, wie erwartet:

class Two : ITwo 
{ 
    public int Thing 
    { 
     get { return 0; } 
    } 

    public int Thing2 
    { 
     get { return 0; } 
    } 
} 
+3

Ah! Das "und Sie können alle vererbten IOne-Methoden als abstrakt erklären" -Bit war der Schlüssel, den ich vermisste. Vielen Dank. – scobi

+1

Das Problem ist, dass Sie noch alle IOne-Methoden in der abstrakten Vertragsklasse ITwoContract angeben müssen. Wenn IOne 50 Methoden sagt, muss ich sie für jede Schnittstelle wiederholen, die von IOne erbt - sehr mühsam und macht Änderungen an IOne schwierig. – Rob

+1

Wenn Sie eine Schnittstelle mit 50 Methoden haben, werden Sie wahrscheinlich jede Veränderung in Bezug auf diese Schnittstelle mühsam und hart finden, weil Sie das Prinzip der einfachen Verantwortlichkeit verletzen werden. –