2009-01-13 16 views
7

Ich finde oft, dass ich eine Eigenschaft schreibe, die träge bewertet wird. Etwas wie:Implementieren einer "LazyProperty" -Klasse - ist das eine gute Idee?

if (backingField == null) 
    backingField = SomeOperation(); 
return backingField; 

Es ist nicht viel Code, aber es hat eine Menge bekommen wiederholt, wenn Sie eine Menge von Eigenschaften haben.

ich über das Definieren einer Klasse denke genannt LazyProperty:

public class LazyProperty<T> 
    { 
    private readonly Func<T> getter; 

    public LazyProperty(Func<T> getter) 
    { 
     this.getter = getter; 
    } 

    private bool loaded = false; 
    private T propertyValue; 

    public T Value 
    { 
     get 
     { 
      if (!loaded) 
      { 
       propertyValue = getter(); 
       loaded = true; 
      } 
      return propertyValue; 
     } 
    } 

    public static implicit operator T(LazyProperty<T> rhs) 
    { 
     return rhs.Value; 
    } 
} 

Das würde mir ermöglichen, ein Feld wie folgt zu initialisieren:

first = new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value }); 

Und dann der Körper der Eigenschaft könnte reduziert werden :

Dies würde von den meisten der Firma verwendet werden, da es in eine gehen würde gemeinsame Klassenbibliothek, die von den meisten unserer Produkte geteilt wird.

Ich kann nicht entscheiden, ob das eine gute Idee ist oder nicht. Ich denke, die Lösungen einige Profis haben, wie:

  • Weniger Code
  • Prettier Code

Auf der anderen Seite würde es schwieriger sein, den Code zu suchen und bestimmen, genau das, was passiert - vor allem, wenn einem Der Entwickler ist mit der LazyProperty-Klasse nicht vertraut.

Was denkst du? Ist das eine gute Idee oder sollte ich es aufgeben? Ist der implizite Operator auch eine gute Idee, oder möchten Sie die Value-Eigenschaft explizit verwenden, wenn Sie diese Klasse verwenden?

Meinungen und Vorschläge sind willkommen :-)

Antwort

7

Nur um allzu pedantisch:

Ihre vorgeschlagene Lösung zu vermeiden Code wiederholen:

private LazyProperty<HeavyObject> first = 
    new LazyProperty<HeavyObject>(() => new HeavyObject { MyProperty = Value }); 
public HeavyObject First { 
    get { 
    return first; 
    } 
} 

ist eigentlich mehr Zeichen als der Code, den Sie nicht wiederholen wollte:

private HeavyObject first; 
public HeavyObject First { 
    get { 
    if (first == null) first = new HeavyObject { MyProperty = Value }; 
    return first; 
    } 
} 

Abgesehen davon denke ich, dass die implizite Besetzung den Code sehr schwer verständlich machte.Ich hätte nicht gedacht, dass eine Methode, die einfach zuerst zurückkehrt, letztendlich ein HeavyObject erzeugt. Ich hätte zumindest die implizite Umwandlung fallen gelassen und zuerst zurückgegeben. Wert von der Eigenschaft.

+0

Ihr Punkt wird über den impliziten Operator notiert. Es ist eines dieser Dinge, über die ich Meinungen brauchte. – driis

+1

Es ist gut pedantisch zu sein. +1. – dalle

1

Ich mag die Idee, dass es viel weniger Code und eleganter ist, aber ich würde über die Tatsache sehr besorgt sein, dass sie es schwer sehen werden und sagen Was ist los. Die einzige Möglichkeit, die ich in Betracht ziehen würde, ist eine Konvention für Variablen, die auf die "faule" Art und Weise gesetzt werden, und auch, wo immer sie benutzt wird, zu kommentieren. Jetzt wird es keinen Compiler oder irgendetwas geben, das diese Regeln durchsetzt, also immer noch YMMV.

Am Ende, für mich, Entscheidungen wie diese kochen auf, wer wird es betrachten und die Qualität dieser Programmierer. Wenn Sie Ihren Mitentwicklern vertrauen können, sie richtig zu benutzen und gut zu kommentieren, dann sollten Sie es tun, aber wenn nicht, ist es besser, wenn Sie es auf leicht verständliche und nachvollziehbare Weise tun./meine 2cents

2

Ich bevorzuge den ersten Code, weil a) es ein so häufiges Muster mit Eigenschaften ist, dass ich es sofort verstehe, und b) der Punkt, den du angesprochen hast: dass es keine versteckte Magie gibt, die du gehen musst um zu verstehen, wo und wann der Wert erhalten wird.

1

Ich glaube nicht, dass es beunruhigend ist, dass ein Entwickler nicht versteht, etwas gegen das zu unternehmen ...

Wenn Sie denken, dass dann Sie nichts für die Angst vor jemand tun konnte nicht verstehen, was Sie getan haben

Sie ein Tutorial oder etwas in einem zentralen Repository schreiben konnte, haben wir hier ein Wiki für diese Art von

Insgesamt stellt fest, ich denke, es ist eine gute Umsetzung Idee (nicht eine Debatte beginnen wollen, ob Lazy Loading eine gute Idee ist oder nicht)

0

ich mag Ihre Lösung, da es sehr klug ist, aber ich Sie nicht denken Gewinnen Sie viel, indem Sie es benutzen. Lazy das Laden eines privaten Feldes in einer öffentlichen Eigenschaft ist definitiv ein Ort, an dem Code dupliziert werden kann. Dies ist mir jedoch immer als ein Muster aufgefallen, das ich anstelle eines Codes verwenden muss, der in einen gemeinsamen Raum umstrukturiert werden muss.

Ihr Ansatz kann in Zukunft zu einem Problem werden, wenn Sie eine Serialisierung durchführen. Außerdem ist es zunächst verwirrender zu verstehen, was Sie mit dem benutzerdefinierten Typ tun.

Insgesamt applaudiere ich Ihrem Versuch und schätze seine Klugheit, würde aber vorschlagen, dass Sie aus den oben genannten Gründen zu Ihrer ursprünglichen Lösung zurückkehren.

4

Sicherlich möchten Sie zumindest, dass der LazyPropery<T> ein Werttyp ist, andernfalls haben Sie Speicher und GC-Druck für jede "lazy-loaded" -Eigenschaft in Ihrem System hinzugefügt.

Auch, was ist mit Multiple-Threaded-Szenarien? Stellen Sie sich zwei Threads vor, die gleichzeitig die Eigenschaft anfordern. Ohne Sperren könnten Sie möglicherweise zwei Instanzen der zugrunde liegenden Eigenschaft erstellen. Um eine Sperrung im allgemeinen Fall zu vermeiden, sollten Sie eine doppelt überprüfte Sperre ausführen.

+0

+1 für die Verriegelung, nicht zu hart in seinen Entwurf zu arbeiten, obwohl –

+0

Ja, ich würde propably eine inhertied Klasse erstellt das gleiche Muster zu implementieren, aber mit Thread-Sicherheit im Wert Getter. Dann könnte der Klassenverbraucher wählen, ob er Gewindesicherheit will/braucht oder nicht. – driis

1

Was ich in diesem Fall mache, ist ich ein Visual Studio code snippet erstellen. Ich denke, das sollten Sie wirklich tun.

Zum Beispiel, wenn ich ASP.NET-Steuerelemente erstellen, habe ich oft mal haben Daten, die im Viewstate viel gespeichert wird, so habe ich einen Code-Schnipsel wie folgt aus:

public Type Value 
{ 
    get 
    { 
     if(ViewState["key"] == null) 
      ViewState["key"] = someDefaultValue; 
     return (Type)ViewState["key"]; 
    } 
    set{ ViewState["key"] = value; } 
} 

diese Weise den Code kann leicht mit nur ein wenig Arbeit erstellt werden (den Typ, den Schlüssel, den Namen und den Standardwert definieren). Es ist wiederverwendbar, aber Sie haben nicht den Nachteil eines komplexen Code, den andere Entwickler möglicherweise nicht verstehen.

0

Persönlich glaube ich nicht, dass die LazyProperty-Klasse wie bietet genug Wert, um es zu rechtfertigen, vor allem unter Berücksichtigung der Nachteile für Werttypen (wie Kent erwähnt). Wenn Sie andere Funktionen benötigen (z. B. Multithread), könnte dies als ThreadSafeLazyProperty-Klasse gerechtfertigt sein.

In Bezug auf die implizite Eigenschaft mag ich die Eigenschaft "Value" besser. Es ist ein bisschen mehr tippen, aber viel klarer für mich.

5

Tun Sie es überhaupt nicht.

Im Allgemeinen diese Art von faul initialisierte Eigenschaften verwendet, ist eine gültige Designwahl in einem Fall: wenn SomeOperation(); eine teure Operation ist (in Bezug auf die I/O, wie wenn es ein DB-Hit erfordert, oder rechnerisch), und wenn Sie sind sicher, dass Sie oft nicht darauf zugreifen müssen.

Das heißt, standardmäßig sollten Sie für eifrige Initialisierung gehen, und wenn Profiler sagt, es ist Ihr Engpass, dann ändern Sie es auf faul Initialisierung.

Wenn Sie das Bedürfnis haben, diese Art von Abstraktion zu erzeugen, ist es ein Geruch.

+0

Er fragt nicht, ob Lazy-ausgewertete Felder gültige Wahl sind (er versteht die Unterscheidung, wann es ist und wann nicht). Er fragt, ob die von ihm präsentierte Lösung eine gute Design-Entscheidung ist. –

+0

Nun, er sagt, dass er eine Menge fauler Inits macht, was mir auch komisch vorkommt. Die meisten Eigenschaften sollten keine faulen Eingaben imo erfordern. –

+1

@petr, Ja, ich weiß, was die Frage war. Ich sage nur, dass das eine völlig schlechte Idee ist und warum. Warnung, sich nicht zu schneiden, ist eine gültige Antwort auf die Frage "Wie schneide ich mich am besten?" –

0

Ich denke, das ist eine interessante Idee. Zuerst würde ich empfehlen, dass Sie die Lazy-Eigenschaft vor dem aufrufenden Code verstecken. Sie möchten nicht in Ihr Domänenmodell eindringen, dass es faul ist. Was du mit dem impliziten Operator machst, behalte das so.

Ich mag, wie Sie diesen Ansatz verwenden können, um die Details der Verriegelung zum Beispiel zu behandeln und wegzusortieren. Wenn Sie das tun, dann denke ich, dass es Wert und Verdienst gibt. Wenn Sie Locking für das Double Lock-Muster hinzufügen, ist es sehr einfach, es falsch zu verstehen.

Verwandte Themen