Ich könnte Code-Verträge missverstehen, aber hier ist meine Situation.
Ich habe den folgenden Code:
%Vor% Ich versuche, einen relativ einfachen Vertrag hinzuzufügen: Contract.Requires (id != 0);
, und ich möchte, dass er auf Fetch
validiert wird. Wenn ich es direkt zu Fetch hinzufüge, erhalte ich die Warnung Method Fetch(int id) implements interface 3rdParty.IFetch<User> and thus cannot add Requires
.
Ich habe eine abstrakte Code-Contracts-Klasse erstellt, die IFetch implementiert und auf / von UserFetch mit den Attributen ContractClass
bzw. ContractClassFor
verweist. Ich bekomme immer noch einen Fehler wie CodeContracts: The class 'FetchUserContracts' is supposed to be a contract class for '3rdParty.IFetch<User>', but that type does not point back to this class.
Da 3rdParty.IFetch jedoch ein generischer Typ ist, glaube ich nicht, dass ich jemals einen Code-Vertrag darauf setzen kann.
Wurde das Problem klargestellt, und wenn ja, wie löse ich es?
Ich glaube, dass Ɖiamond ǤeezeƦs Antwort richtig ist. Ich werde nur ein bisschen Erklärung hinzufügen.
Sie können einer Methode in einem geschlossenen Konstruktionstyp (z. B. Contract.Requires
) keine IFetch<User>
-Dekoration hinzufügen. Sie müssen es dem offenen Konstruktionstyp hinzufügen ( IFetch<>
). Der Grund dafür ist genau der gleiche Grund, warum Sie einer konkreten Methode, die zum Implementieren einer Schnittstelle verwendet wird, keine Contract.Requires
Dekoration hinzufügen können: Codeverträge sind so konzipiert, dass sie zur Kompilierzeit verifizierbar sind, wenn der vollständige Typ einer Objektinstanz vorhanden sein kann unbekannt.
Angenommen, Sie hätten den Vertrag auf die konkrete Methodenimplementierung anwenden können.
%Vor%Angenommen, jemand hat versucht, eine Variable des Schnittstellentyps zu verwenden.
%Vor% Ermöglicht dies eine Vertragsverletzung oder nicht? Es ist unmöglich zu sagen, weil wir nicht wissen, was der konkrete Typ von fetch
zur Laufzeit sein wird.
Wenn Sie den Vertrag auf einen bestimmten geschlossenen Konstruktionstyp wie IFetch<User>
setzen, wird dieses Problem nicht gelöst. Wir wissen immer noch nicht, welcher Typ T im aufrufenden Code ist.
Das Liskow-Substitutionsprinzip, das ein Grundpfeiler der Objektorien-Programmierung ist, bedeutet, dass wir niemals vom Laufzeittyp eines Objekts ausgehen können, der über den Typ der Variablen hinausgeht. Und da der Typ der Variablen eine generische Schnittstelle sein kann, können Code-Verträge den Aufrufer nicht zusätzlich belasten, als dies in der generischen Schnittstellendefinition der Fall ist.
Daher muss Contract.Requires
auf den offen konstruierten Typ gesetzt werden, so dass jedes Objekt, das die Schnittstelle implementiert, die Anforderung hat, und jeder potenzielle Aufruf der Methode über eine Variable des Schnittstellentyps kann auf Korrektheit mit überprüft werden in Bezug auf diese Anforderung.
Sie müssen eine abstrakte Klasse erstellen, um den Vertrag zu implementieren, zum Beispiel:
%Vor%Und füge das folgende ContractClass-Attribut zu IFetch hinzu:
%Vor%Tags und Links c# code-contracts