C # -Delegierte sind unveränderlich - aber warum ist das wichtig?

8

Dies ist eine Folgefrage zu dieser anderen Frage.

Hintergrund

Beim Arbeiten mit dem MSDN Delegates Tutorial (C #) sehe ich Folgendes:

Beachten Sie, dass sich die Methode, der er zugeordnet ist, nach dem Erstellen eines Delegaten nie ändert - Delegatenobjekte sind unveränderlich.

Und dann sehe ich im Codebeispiel Folgendes (ein wenig über den Code verteilen):

public delegate void ProcessBookDelegate(Book book);

bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(totaller.AddBookToTotal));

Die Frage

Bei der Art und Weise, wie der Code hier geschrieben wird, wird für jeden Prozess ein neuer Delegat erstellt. Ich vermute, die Unveränderlichkeit ist relevant, wenn Sie versuchen, Dinge wie zu tun

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);
ProcessBookDelegate thisIsATest = new ProcessBookDelegate(totaller.AddBookToTotal);

was soll ... noch kompilieren wann thisIsATestist unveränderlich? Welches Problem hat Microsoft gelöst, indem es unveränderlich gemacht wurde? Auf welche Probleme würden wir stoßen, wenn C # 6 die Delegierten veränderlich machen würde?

BEARBEITEN

Ich glaube, die Unveränderlichkeit wird dies verhindern:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);

thisIsATest.ChangeTheDelegateInABadFashion();

someFunction(thisIsATest); //This function works as normal
                           //because the delegate is unchanged
                           //due to immutability

aber die Unveränderlichkeit wird dies NICHT verhindern:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);

thisIsATest = new ProcessBookDelegate(ChangeTheDelegateInABadFashion());

someFunction(thisIsATest); //This function works weird now because
                           //it expected the unchanged delegate

Bin ich in diesem Verständnis richtig?

medivh
quelle

Antworten:

15

Ich denke, Sie verwechseln, was Unveränderlichkeit bedeutet.

Was Unveränderlichkeit nicht ist

Schauen Sie sich dieses Beispiel an:

string s = "Hello";
s = "World";

Sind strings unveränderlich? Ja.
Wird dies kompiliert? Ja.
Haben wir die String-Instanz in irgendeiner Weise geändert? Nein .

Wir nehmen keine Änderungen an vor "Hello". Wir erstellen eine Zeichenfolge, weisen sie der Variablen zu s, erstellen dann eine neue string und überschreiben die Variable smit dieser neuen string. Unveränderlichkeit spielt hier keine Rolle.

Was Unveränderlichkeit ist

Wenn wir so etwas versuchen würden:

s.MutateInSomeWay();

Dabei MutateInSomeWayhandelt es sich um eine Methode, die die Zeichenfolge "Hello"(den Wert von s) selbst ändert und aufgrund der Unveränderlichkeit der Zeichenfolge nicht gültig ist.

Alle Methoden, stringdie es in irgendeiner Weise ändern, ändern es nicht wirklich. Sie erstellen ein neues stringmit dem geänderten Wert und geben es an den Aufrufer zurück.

aber die Unveränderlichkeit wird dies NICHT verhindern:

ProcessBookDelegate thisIsATest = new ProcessBookDelegate(PrintTitle);  
thisIsATest = new ProcessBookDelegate(ChangeTheDelegateInABadFashion());
someFunction(thisIsATest); //This function works weird now because
//it expected the unchanged delegate

Bin ich in diesem Verständnis richtig?

Ja, Unveränderlichkeit wird es nicht verhindern, da es vollkommen gültig ist und Sie kein Objekt mutiert haben. Natürlich ist Ihnen nicht ganz klar, was es ist ChangeTheDelegateInABadFashion(), daher ist es schwierig, genau zu sein.

Rotem
quelle
1
Es ist erwähnenswert, dass der einzige Aspekt eines Delegaten, der unveränderlich ist, die Methode ist, die aufgerufen wird, und die Identität seines Ziels. Das Zielobjekt selbst ist häufig veränderlich (tatsächlich besteht der gesamte Zweck vieler Delegierter darin, das Zielobjekt zu mutieren!), Und selbst wenn der Delegat den einzigen Verweis auf ein Zielobjekt enthält, wäre es völlig legitim, wenn Func<int>1 das erste zurückgibt Mal heißt es, 2 die Sekunde usw. - dies verhält sich im Wesentlichen wie ein veränderliches Objekt.
Supercat
Unveränderlichkeit tritt ein, wenn Sie versuchen, eine Zeichenfolge wie diese zu ändern. s[2] = 't'.
M. Kazem Akhgary 3.
Als jemand, der gerade C # aufnimmt, wünschte ich, ich könnte die Antwort von @ supercat hier direkt mit anderen teilen. Es macht für mich keinen Sinn, Delegierte als unveränderlich zu bezeichnen, da sie möglicherweise beliebigen Code enthalten, der beliebige Mutationen aufweisen kann, die von außerhalb des Delegierten sichtbar sind.
Trptcolin
2

Standardgewindesicherheit glaube ich; Wenn Sie wissen, dass sich ein Delegierter niemals ändern wird, können Sie einige Annahmen darüber treffen

Insbesondere können Sie sicher sein, dass ein böser Code den Delegierten, den Sie an mehrere Funktionen übergeben, nicht ändern kann (auch nicht aus Versehen).

Dies kann dazu führen, dass Fehler nur schwer aufgespürt werden können und der Programmierer sich fragt, warum sein Delegierter nicht angerufen wurde

Ratschenfreak
quelle
Da Delegaten an veränderbare Objekte gebunden werden können, besteht kein Grund zu der Annahme, dass wiederholte Aufrufe an denselben Delegaten dasselbe bewirken. In Bezug auf den Thread-Sicherheitspunkt haben Sie jedoch Recht: Der Zweck, Delegaten unveränderlich zu machen, besteht darin, sicherzustellen, dass sie immer an eine Methode gebunden sind, die mit dem Typ der angehängten Instanz kompatibel ist. Wenn sich Methode und Instanz getrennt ändern könnten, könnten schlimme Dinge passieren.
Supercat
2

Die einfache Antwort lautet: Mutieren eines Delegierten macht wenig Sinn. Ein Delegat ist in hohem Maße eine Referenz auf eine Funktion, eine Reihe von ausführendem Code. Mutation, die darauf hindeutet, dass Sie diese Funktion mutieren.

Fragen Sie sich, wie würde diese Methode bei einem Delegierten aussehen und was würde sie tun? In gewissem Sinne würde es den Code dieser Funktion neu schreiben. Dies eröffnet der C # -Spezifikation und den Compiler-Implementierungen eine enorme (fast unlösbare) Komplexität für sehr geringen Nutzen bei hohen Leistungskosten. Daher die Einschränkung.

Nathan Dykman
quelle