423 Stimmen

Warum sind C# 4 optionale Parameter auf Schnittstelle definiert nicht auf implementierende Klasse erzwungen?

Ich habe bemerkt, dass mit den optionalen Parametern in C# 4, wenn Sie einen optionalen Parameter auf einer Schnittstelle angeben Sie nicht, dass müssen diesen Parameter für jede implementierende Klasse optional machen:

public interface MyInterface
{
    void TestMethod(bool flag = false);
}

public class MyClass : MyInterface
{
    public void TestMethod(bool flag)
    {
        Console.WriteLine(flag);
    }
}

und deshalb:

var obj = new MyClass();        
obj.TestMethod(); // compiler error

var obj2 = new MyClass() as MyInterface;
obj2.TestMethod(); // prints false

Weiß jemand, warum optionale Parameter auf diese Weise funktionieren sollen?

Einerseits nehme ich an, dass die Möglichkeit, alle in den Schnittstellen festgelegten Standardwerte außer Kraft zu setzen, nützlich ist, obwohl ich mir ehrlich gesagt nicht sicher bin, ob man überhaupt in der Lage sein sollte, Standardwerte in der Schnittstelle festzulegen, da dies eine Entscheidung der Implementierung sein sollte.

Auf der anderen Seite bedeutet diese Trennung, dass Sie die konkrete Klasse und die Schnittstelle nicht immer austauschbar verwenden können. Dies wäre natürlich kein Problem, wenn der Standardwert in der Implementierung angegeben ist, aber wenn Sie Ihre konkrete Klasse als Schnittstelle offenlegen (z. B. mithilfe eines IOC-Frameworks, um die konkrete Klasse zu injizieren), dann hat es wirklich keinen Sinn, den Standardwert zu haben, da der Aufrufer ihn sowieso immer bereitstellen muss.

279voto

Eric Lippert Punkte 628543

UPDATE: Diese Frage war das Thema meines Blogs vom 12. Mai 2011. Vielen Dank für die tolle Frage!

Angenommen, Sie haben eine Schnittstelle, wie Sie sie beschreiben, und hundert Klassen, die sie implementieren. Dann beschließen Sie, einen der Parameter einer der Methoden der Schnittstelle optional zu machen. Halten Sie es für richtig, dass der Compiler den Entwickler zwingt, jede Implementierung dieser Schnittstellenmethode zu finden und den Parameter ebenfalls optional zu machen?

Angenommen, wir tun das. Nehmen wir nun an, der Entwickler hätte den Quellcode für die Implementierung nicht:


// in metadata:
public class B 
{ 
    public void TestMethod(bool b) {}
}

// in source code
interface MyInterface 
{ 
    void TestMethod(bool b = false); 
}
class D : B, MyInterface {}
// Legal because D's base class has a public method 
// that implements the interface method

Wie soll der Autor von D dies bewerkstelligen? Müssen sie in Ihrer Welt den Autor von B anrufen und ihn bitten, ihnen eine neue Version von B zu liefern, in der die Methode einen optionalen Parameter hat?

Das wird nicht klappen. Was wäre, wenn zwei Leute den Autor von B anrufen, und einer von ihnen will, dass die Vorgabe wahr ist und einer, dass sie falsch ist? Was ist, wenn der Autor von B sich einfach weigert, mitzuspielen?

Vielleicht müssten sie in diesem Fall sagen:

class D : B, MyInterface 
{
    public new void TestMethod(bool b = false)
    {
        base.TestMethod(b);
    }
}

Die vorgeschlagene Funktion scheint für den Programmierer eine Menge Unannehmlichkeiten mit sich zu bringen, ohne dass die Repräsentativität entsprechend erhöht wird. Welchen zwingenden Vorteil bietet diese Funktion, der die erhöhten Kosten für den Benutzer rechtfertigt?


UPDATE: In den Kommentaren unten schlägt supercat eine Sprachfunktion vor, die der Sprache wirklich mehr Macht verleihen und einige Szenarien ermöglichen würde, die dem in dieser Frage beschriebenen ähneln. Zu Ihrer Information: Dieses Feature - Standardimplementierungen von Methoden in Interfaces - wird in C# 8 hinzugefügt werden.

51voto

CodesInChaos Punkte 103089

Ein optionaler Parameter ist lediglich mit einem Attribut versehen. Dieses Attribut weist den Compiler an, den Standardwert für diesen Parameter an der Aufrufstelle einzufügen.

Der Anruf obj2.TestMethod(); wird ersetzt durch obj2.TestMethod(false); wenn der C#-Code zu IL kompiliert wird, und nicht zur JIT-Zeit.

In gewisser Weise ist es also immer der Aufrufer, der den Standardwert mit optionalen Parametern bereitstellt. Dies hat auch Auswirkungen auf die binäre Versionierung: Wenn Sie den Standardwert ändern, aber den aufrufenden Code nicht neu kompilieren, wird er weiterhin den alten Standardwert verwenden.

Auf der anderen Seite bedeutet diese Trennung, dass Sie die konkrete Klasse und die Schnittstelle nicht immer austauschbar verwenden können.

Das geht schon nicht mehr, wenn die Schnittstellenmethode explizit umgesetzt .

34voto

Olhovsky Punkte 5286

Denn Standardparameter werden zur Kompilierzeit aufgelöst, nicht zur Laufzeit. Die Standardwerte gehören also nicht zu dem aufgerufenen Objekt, sondern zu dem Referenztyp, über den es aufgerufen wird.

7voto

Ariel Arjona Punkte 172

Optionale Parameter sind eine Art Makrosubstitution, soweit ich weiß. Vom Standpunkt der Methode aus sind sie nicht wirklich optional. Ein Artefakt davon ist das Verhalten, das Sie sehen, wo Sie unterschiedliche Ergebnisse erhalten, wenn Sie auf eine Schnittstelle casten.

2voto

Harshdeep Singh Punkte 195

Ich möchte hier nur meine Meinung dazu sagen, denn die anderen Antworten liefern zwar vernünftige Erklärungen, aber keine, die mich völlig zufrieden stellen.

Optionale Parameter sind syntaktischer Zucker für die Injektion des Standardwerts an der Aufrufstelle zur Kompilierzeit. Dies hat nichts mit Schnittstellen/Implementierungen zu tun und kann als reiner Nebeneffekt von Methoden mit optionalen Parametern betrachtet werden. Wenn Sie also die Methode aufrufen,

public void TestMethod(bool value = false) { /*...*/ }

wie SomeClass.TestMethod() ist es eigentlich SomeClass.TestMethod(false) . Wenn Sie diese Methode über eine Schnittstelle aufrufen, hat die Methodensignatur bei der statischen Typüberprüfung den optionalen Parameter. Wenn Sie diese Methode auf einer Instanz einer abgeleiteten Klasse aufrufen, die den optionalen Parameter nicht hat, hat die Methodensignatur bei statischer Typprüfung den optionalen Parameter nicht und muss mit vollständigen Argumenten aufgerufen werden.

Aufgrund der Art und Weise, wie optionale Parameter implementiert werden, ist dies das natürliche Ergebnis der Entwicklung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X