2017-05-10 2 views
4

Ich versuche Covariance und LSP zu verstehen. Von this question kann ich sehen, dass C# keine Rückgabetyp-Kovarianz unterstützt. Liskov substitution principle erzwingt jedoch die Kovarianz für den Rückgabetyp.C# Rückgabetyp Kovarianz und Liskov Substitutionsprinzip

Bedeutet es, dass es unmöglich ist, dieses Prinzip in C# anzuwenden? Oder habe ich etwas missverstanden?

+2

Sie mißverstehen. Die Kovarianz vom Rückgabetyp ist nicht dasselbe wie der Rückgabewert, der kovariant ist. Es bedeutet nur, dass Sie die Methode nicht mit einem anderen Rückgabetyp überschreiben können. Es ist immer noch vollkommen in Ordnung, eine Instanz eines abgeleiteten Typs von einer Methode zurückzugeben, die den Basistyp zurückgibt - ein abgeleiteter Typ ist immer noch ein Subtyp des Basistyps; LSP passt immer noch gut. – Luaan

Antwort

4

C# kann immer noch das Substitutionsprinzip Liskov anzuwenden.

Bedenken Sie:

public class Base1 
{ 
} 

public class Derived1 : Base1 
{ 
} 

public class Base2 
{ 
    public virtual Base1 Method() 
    { 
     return new Base1(); 
    } 
} 

public class Derived2 : Base2 
{ 
    public override Base1 Method() 
    { 
     return new Derived1(); 
    } 
} 

Wenn C# kovarianten Rückgabetypen unterstützt, dann ist die Überschreibung für Method() in Base2 konnte thusly deklariert werden:

public class Derived2 : Base2 
{ 
    public override Derived1 Method() 
    { 
     return new Derived1(); 
    } 
} 

C# dies nicht zulässt, und Sie müssen die erklären Rückgabetyp der gleiche wie in der Basisklasse, nämlich Base1.

Dies macht jedoch keine Verletzung des Liskov-Substitutionsprinzips.

Bedenken Sie:

Base2 test = new Base2(); 
Base1 item = test.Method(); 

Im Vergleich zu:

Base2 test = new Derived2(); 
Base1 item = test.Method(); 

Wir sind vollständig in der Lage new Base2() mit new Derived2() ohne Probleme zu ersetzen. Dies entspricht dem Liskov-Substitutionsprinzip.

0

Da die Rückgabetyp-Kovarianz in C# nicht unterstützt wird, ist es nicht möglich, das Liskov-Prinzip zu verletzen, wenn es zur Rückgabetyp-Kovarianz kommt.

Gute Quelle ist diese Rede von S.O.L.I.D Prinzipien in C#: https://youtu.be/gwIS9cZlrhk?t=1886

0

C# haben eine begrenzte Unterstützung für diese Funktion durch Generika und den generischen Modifikator out. (Siehe: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-generic-modifier)

Die Unterstützung ist begrenzt, da es nur mit Schnittstellen funktioniert. Umschreiben die akzeptierte Antwort:

public class Base1 
{ 
} 

public class Derived1 : Base1 
{ 
} 

public interface Base2<out T> where T : Base1 
{ 
    T Method(); 
} 

public class Derived2 : Base2<Derived1> 
{ 
    public Derived1 Method() 
    { 
     return new Derived1(); 
    } 
} 

In diesem Fall Derived2 wird nicht nur Base2<Derived1> implementieren, sondern es wird auch Base2<Base1> implementieren.

Das Prinzip wirksam wird, denn wenn man Method durch die Base2<Base1> Schnittstelle aufrufen wird es Base1 Rückgabetyp haben, aber wenn man es durch Derived2 nennen es Derived1 Rückgabetyp haben.

Ebenso können Sie Parameter Kontra mit dem in generic Modifikator implementieren: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-generic-modifier

Hinweis, dass es nicht möglich ist, das Prinzip zu verletzen.Wenn in dem obigen Beispiel Sie das out Schlüsselwort zum in Keyword ändern, wird die Quelle nicht kompilieren, und Sie erhalten die folgende Fehlermeldung erhalten:

Error CS1961 Invalid variance: The type parameter 'T' must be covariantly valid on 'Base2<T>.Method()'. 'T' is contravariant. 
Verwandte Themen