72 Stimmen

C#-Eigenschaft und ref-Parameter, warum kein Zucker?

Ich bin gerade bei der Arbeit in C# auf diese Fehlermeldung gestoßen

Eine Eigenschaft oder ein Indexer darf nicht als out- oder ref-Parameter übergeben werden

Ich wusste, was die Ursache dafür war, und habe eine schnelle Lösung gefunden, indem ich eine lokale Variable des richtigen Typs erstellt und die Funktion mit ihr als out / ref und weisen ihn dann wieder der Eigenschaft zu:

RefFn(ref obj.prop);

wird zu

{
    var t = obj.prop;
    RefFn(ref t);
    obj.prop = t;
}

Dies würde natürlich fehlschlagen, wenn die Eigenschaft get und set im aktuellen Kontext nicht unterstützt.

Warum macht C# das nicht einfach für mich?


Die einzigen Fälle, in denen ich mir vorstellen kann, dass dies Probleme verursachen könnte, sind:

  • Einfädeln
  • Ausnahmen

Für Threading, dass die Transformation beeinflusst, wenn die Schreibvorgänge passieren (nach dem Funktionsaufruf vs. im Funktionsaufruf), aber ich eher vermuten, dass jeder Code, der auf, dass zählt würde wenig Sympathie erhalten, wenn es bricht.

Bei Ausnahmen wäre die Frage, was passiert, wenn die Funktion einer von mehreren Ausnahmen zugewiesen wird. ref Parameter als Würfe? Jede triviale Lösung würde dazu führen, dass alle oder keiner der Parameter zugewiesen wird, obwohl einige zugewiesen werden sollten und einige nicht. Auch hier glaube ich nicht, dass dies eine unterstützte Verwendung der Sprache wäre.


Hinweis: Ich verstehe, warum diese Fehlermeldung erzeugt wird. Was ich suche, ist die Begründung, warum C# nicht automatisch die triviale Abhilfe implementiert.

31voto

David Morton Punkte 15950

Denn Sie übermitteln die Ergebnis des Indexers, der eigentlich das Ergebnis eines Methodenaufrufs ist. Es gibt keine Garantie, dass die Indexer-Eigenschaft auch einen Setter hat, und die Übergabe per ref würde zu einer falschen Sicherheit für den Entwickler führen, wenn er denkt, dass seine Eigenschaft gesetzt wird, ohne dass der Setter aufgerufen wird.

Technisch gesehen übergeben ref und out die Speicheradresse des Objekts, das ihnen übergeben wurde, und um eine Eigenschaft zu setzen, müssen Sie den Setter aufrufen, so dass es keine Garantie dafür gibt, dass die Eigenschaft tatsächlich geändert wird, insbesondere wenn der Eigenschaftstyp unveränderlich ist. ref und out sind nicht nur einstellen. den Wert bei der Rückkehr der Methode, übergeben sie den tatsächlichen Speicherverweis auf das Objekt selbst.

16voto

user7116 Punkte 61589

Eigenschaften sind nichts weiter als syntaktischer Zucker für die in Java üblichen Methoden getX/setX. Es macht nicht viel Sinn für "ref" auf eine Methode. In Ihrem Fall würde es Sinn machen, weil Ihre Eigenschaften sind lediglich stubbing out Felder. Eigenschaften müssen nicht nur Stubs sein, daher kann das Framework 'ref' auf Eigenschaften nicht zulassen.

EDIT : Nun, die einfache Antwort ist, dass die bloße Tatsache, dass ein Property Getter oder Setter weit mehr als nur das Lesen/Schreiben eines Feldes beinhalten könnte, es nicht wünschenswert macht, ganz zu schweigen von möglicherweise unerwartet, die Art von Zucker, die Sie vorschlagen, zu erlauben. Das soll nicht heißen, dass ich diese Funktionalität nicht schon einmal gebraucht habe, ich verstehe nur, warum man sie nicht zur Verfügung stellen möchte.

12voto

Marc Gravell Punkte 970173

Nur zur Information: C# 4.0 se etwas haben wie diesen Zucker, aber nur beim Aufruf von Interop-Methoden - zum Teil aufgrund der schieren Neigung von ref in diesem Szenario. Ich habe es (in der CTP) noch nicht viel getestet; wir werden sehen, wie es sich entwickelt...

8voto

Brian Rasmussen Punkte 112118

Sie können Felder mit ref / out aber keine Eigenschaften. Der Grund dafür ist, dass Eigenschaften eigentlich nur eine Syntaxabkürzung für spezielle Methoden sind. Der Compiler übersetzt get / set Eigenschaften in entsprechende get_X y set_X Methoden, da die CLR keine unmittelbare Unterstützung für Eigenschaften bietet.

6voto

Mark Rendle Punkte 8989

Es wäre nicht thread-sicher; wenn zwei Threads gleichzeitig ihre eigenen Kopien des Eigenschaftswerts erstellen und sie als ref-Parameter an Funktionen übergeben, landet nur eine davon wieder in der Eigenschaft.

class Program
{
  static int PropertyX { get; set; }

  static void Main()
  {
    PropertyX = 0;

    // Sugared from: 
    // WaitCallback w = (o) => WaitAndIncrement(500, ref PropertyX);
    WaitCallback w = (o) => {
      int x1 = PropertyX;
      WaitAndIncrement(500, ref x1);
      PropertyX = x1;
    };
    // end sugar

    ThreadPool.QueueUserWorkItem(w);

    // Sugared from: 
    // WaitAndIncrement(1000, ref PropertyX);
    int x2 = PropertyX;      
    WaitAndIncrement(1000, ref x2);
    PropertyX = x2;
    // end sugar

    Console.WriteLine(PropertyX);
  }

  static void WaitAndIncrement(int wait, ref int i)
  {
    Thread.Sleep(wait);
    i++;
  }
}

PropertyX wird als 1 angezeigt, während ein Feld oder eine lokale Variable 2 sein würde.

Dieses Codebeispiel verdeutlicht auch die Schwierigkeiten, die durch Dinge wie anonyme Methoden entstehen, wenn man den Compiler bittet, zuckrige Dinge zu tun.

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