Ich möchte auf einen bestimmten Punkt eingehen, den Eric Lippert in seiner Antwort angesprochen hat, und einen besonderen Anlass ins Rampenlicht rücken, der von niemand anderem berührt wurde. Eric sagte:
[...] Eine Zuordnung hinterlässt fast immer den Wert, der gerade in einem Register zugewiesen wurde.
Ich möchte sagen, dass die Zuweisung immer den Wert hinterlässt, den wir versucht haben, unserem linken Operanden zuzuweisen. Nicht nur "fast immer". Aber ich weiß es nicht, weil ich dieses Problem in der Dokumentation nicht kommentiert habe. Es könnte theoretisch ein sehr effektiv implementiertes Verfahren sein, den linken Operanden "zurückzulassen" und nicht neu zu bewerten, aber ist es effizient?
'Effizient' ja für alle Beispiele, die bisher in den Antworten dieses Threads erstellt wurden. Aber effizient bei Eigenschaften und Indexern, die get- und set-Accessoren verwenden? Überhaupt nicht. Betrachten Sie diesen Code:
class Test
{
public bool MyProperty { get { return true; } set { ; } }
}
Hier haben wir eine Eigenschaft, die nicht einmal ein Wrapper für eine private Variable ist. Wann immer er aufgefordert wird, wird er wahr zurückkehren, wann immer jemand versucht, seinen Wert festzulegen, wird er nichts tun. Wenn also diese Eigenschaft bewertet wird, muss er wahr sein. Mal sehen was passiert:
Test test = new Test();
if ((test.MyProperty = false) == true)
Console.WriteLine("Please print this text.");
else
Console.WriteLine("Unexpected!!");
Ratet mal, was es druckt? Es wird gedruckt Unexpected!!. Wie sich herausstellt, wird der Set-Accessor tatsächlich aufgerufen, was nichts bewirkt. Danach wird der get accessor überhaupt nicht mehr aufgerufen. Die Zuordnung hinterlässt einfach den falseWert, den wir versucht haben, unserem Eigentum zuzuweisen. Und dieser falseWert wird von der if-Anweisung ausgewertet.
Ich werde mit einem Beispiel aus der Praxis abschließen, das mich dazu gebracht hat, dieses Problem zu untersuchen. Ich habe einen Indexer erstellt, der ein praktischer Wrapper für eine Sammlung ( List<string>) war, die eine Klasse von mir als private Variable hatte.
Der an den Indexer gesendete Parameter war eine Zeichenfolge, die als Wert in meiner Sammlung behandelt werden sollte. Der get-Accessor würde einfach true oder false zurückgeben, wenn dieser Wert in der Liste vorhanden ist oder nicht. Daher war der get-Accessor eine andere Möglichkeit, die List<T>.ContainsMethode zu verwenden.
Wenn der Set-Accessor des Indexers mit einer Zeichenfolge als Argument aufgerufen wurde und der rechte Operand ein Bool war true, würde er diesen Parameter zur Liste hinzufügen. Wenn jedoch derselbe Parameter an den Accessor gesendet wurde und der richtige Operand ein Bool war false, löschte er stattdessen das Element aus der Liste. Daher wurde der Set-Accessor als bequeme Alternative zu List<T>.Addund verwendet List<T>.Remove.
Ich dachte, ich hätte eine ordentliche und kompakte "API", die die Liste mit meiner eigenen Logik umschließt, die als Gateway implementiert ist. Mit Hilfe eines Indexers allein konnte ich viele Dinge mit ein paar Tastenanschlägen erledigen. Wie kann ich beispielsweise versuchen, meiner Liste einen Wert hinzuzufügen und zu überprüfen, ob er dort enthalten ist? Ich dachte, dies sei die einzige notwendige Codezeile:
if (myObject["stringValue"] = true)
; // Set operation succeeded..!
Aber wie mein früheres Beispiel gezeigt hat, wurde der get-Accessor, der sehen soll, ob der Wert wirklich in der Liste enthalten ist, nicht einmal aufgerufen. Der trueWert blieb immer zurück und zerstörte effektiv die Logik, die ich in meinem get accessor implementiert hatte.