2010-09-15 6 views
7

Gibt es in C# eine Möglichkeit, eine Eigenschaft als deterministisch zu kennzeichnen?Determinismus der Eigenschaft

Der Grund, warum ich frage, ist, dass ich oft eine lokale Variable deklariere und eine Eigenschaft darin einlese, anstatt auf die Eigenschaft mehrere Male zuzugreifen.

Gibt es eine Möglichkeit, die Eigenschaft als deterministisch zu dekorieren, so dass der Compiler dann mehrere Zugriffe auf diese Eigenschaft optimieren könnte? Ich vermute in einem solchen Szenario, dass die Klasse unveränderlich sein und als solche dekoriert sein müsste.

Ist das etwas, das überhaupt existiert, oder halte ich mich an Strohhalmen fest?

Antwort

7

Wenn die Eigenschaft ist einfach, wie eine implizite Eigenschaft:

public int X { get; set; } 

oder aus einer lokalen Variablen zu lesen:

public int X { get { return _x; } } 

dann der Compiler den Code optimieren, so dass es keinen Unterschied zwischen mehrere Male auf die Eigenschaft zugreifen und die Eigenschaft in eine Variable einfügen und darauf zugreifen.

Ich verifiziert dies durch den Vergleich von 100 Millionen Iterationen des Zugriffs auf eine Eigenschaft zehn Mal und das Kopieren der Eigenschaft auf eine Variable und den Zugriff, dass zehn mal, und es gibt keinen messbaren Unterschied überhaupt.

Im Allgemeinen sollten die Eigenschaften leicht sein, so dass Sie nicht jedes Mal, wenn Sie darauf zugreifen, mit einer schweren Verarbeitung rechnen müssen.Wenn der Wert für die Eigenschaft teuer zu bekommen ist, sollte die Klasse den Wert intern zwischenspeichern, so dass beim Lesen der Eigenschaft nur die kostspielige Operation das erste Mal ausgeführt wird (Lazy-Loading-Muster).

Wenn eine Eigenschaft jedes Mal teuer ist, sollte sie keine Eigenschaft sein, sondern eine Getter-Methode.

+0

+1 - Nur eine Frage - wenn der Compiler diese Optimierung trotzdem macht, wie würde er Änderungen am Objekt auf nicht unveränderlichen Objekten berücksichtigen - ob das vom selben Thread war oder nicht? Ist es möglich, dass Sie gerade bestätigt haben, dass Eigentum auf einem einfachen Grundstück eine sehr geringe Summe kostet, in welchem ​​Fall ich aufhören sollte, anal darüber zu sein? :) –

+0

@Matt Whitfield: Wenn der Code optimiert ist, wird die einfache Eigenschaft interniert werden. Das Lesen der Eigenschaft ruft einen Eigenschaftsgetter nicht auf, um den Wert zurückzugeben, sondern erhält den Wert direkt, als ob Sie auf eine öffentliche Variable in der Klasse zugreifen würden. Im C# -Code erhalten Sie die gewünschte Abstraktion und Isolation in OOP-Code, aber im kompilierten Code erhalten Sie die Geschwindigkeit von öffentlichen Variablen. :) – Guffa

+0

danke - Ich werde das akzeptieren, weil der Kommentar, den du da hast, das Bit ist, das mir das Verständnis gibt, nach dem ich gesucht habe, als ich die Frage gestellt habe. –

0

Wenn das Backing-Feld Ihrer Property nicht readonly ist, wie werden Sie Threading-Probleme berücksichtigen?

5

Es gibt keinen Mechanismus in C#, mit dem Sie konstante Eigenschaften-Getter einführen können, d. H. Getter, die den Zustand des Objekts nicht ändern.

Die Microsoft-Dokumentation einfach empfiehlt not to introduce any side-effects in Ihrem Getter:

Es ist ein schlechter Programmierstil, den Zustand des Objekts zu ändern, indem Sie den get-Zugriff verwendet wird. Zum Beispiel erzeugt der folgende Zugriffsmechanismus den Nebeneffekt des Änderns des Zustands des Objekts jedes Mal, wenn auf das Nummernfeld zugegriffen wird.

private int number; 
public int Number 
{ 
    get 
    { 
     return number++; // Don't do this 
    } 
} 

Wie durch Daren erwähnt, zu prüfen, ein weiterer Aspekt Multi-Threading ist (es sei denn, Ihr Ziel ist es wirklich unveränderlich). Was passiert, wenn ein anderer Thread den Objektstatus geändert hat, sodass der Getter beim zweiten Aufruf einen anderen Wert zurückgibt? Es gibt keine einfache Möglichkeit für den Compiler, irgendwelche Garantien zu geben, z.B. im Szenario unter:

class List 
{ 
    IList data; 

    // called several times on thread A 
    // property has no side-effects 
    public int Count { get data.Length; } 

    // called several times on thread B 
    public void Add(object o) 
    { 
     data.Add(o); 
    } 
} 
+0

DateTime.Now ist eine Eigenschaft, die den Status nicht ändert, aber den Wert trotzdem ändert. Viele andere Eigenschaften spiegeln den Zustand wider, der auf andere Weise als nur durch den Get-Setter geändert werden kann. –

+0

@ Albin Sunnanbo: 'DateTime.Now' ist hier kein gutes Beispiel, da es statisch ist und * einen neuen Werttyp * zurückgibt. Es gibt weder einen Status noch einen Wert. Die Sache ist, dass das OP einen Mechanismus haben möchte, der garantiert, dass nachfolgende Aufrufe derselben Eigenschaft (zumindest in einer single-threaded-Umgebung) dasselbe Ergebnis liefern. –

+0

+1, das bekommt definitiv eine Stimme, aber die Sache, die ich mich wirklich wundere, ist, wenn Sie die Empfehlungen befolgt haben, gibt es eine Möglichkeit, den Compiler zu realisieren, dass mehrere Eigenschaft erhält den gleichen Wert und damit zurück kompilieren Sie sie so, als würden Sie zuerst eine lokale Variable deklarieren, wenn Sie den gleichen Eigenschaftswert mehrmals im selben Bereich verwenden. –

2

Ich glaube, du bist für readonly suchen, aber ich bin nicht sicher, wie die Leistung auf eine lokale Variable verglichen wird. Und es gilt nur für Felder, nicht für Eigenschaften.

Darüber hinaus impliziert readonly nicht Determinismus.

bedeutet nur, dass das FixedList-Objekt nicht ersetzt werden kann, aber der Inhalt kann noch geändert werden.

Verwandte Themen