2011-01-06 7 views
8

Ich bin gerade dabei, eine weit verbreitete Klasse zu ändern, um so viel von der teuren Initialisierung aus dem Klassenkonstruktor in Lazy Initialized-Eigenschaften zu verschieben. Unten ist ein Beispiel (in C#):Methoden für Lazy Initialisierung mit Eigenschaften

Vorher:

public class ClassA 
{ 
    public readonly ClassB B; 

    public void ClassA() 
    { 
     B = new ClassB(); 
    } 
} 

Nach:

public class ClassA 
{ 
    private ClassB _b; 

    public ClassB B 
    { 
     get 
     { 
      if (_b == null) 
      { 
       _b = new ClassB(); 
      } 

      return _b; 
     } 
    } 
} 

Es gibt eine faire einige dieser Eigenschaften in der Klasse bin ich zu verändern, und einige werden in bestimmten Kontexten nicht verwendet (daher die Faulheit), aber wenn sie verwendet werden, werden sie wahrscheinlich wiederholt aufgerufen.

Leider werden die Eigenschaften oft auch innerhalb der Klasse verwendet. Dies bedeutet, dass die private Variable (_b) möglicherweise direkt von einer Methode verwendet werden kann, ohne dass sie initialisiert wird.

Gibt es eine Möglichkeit, nur die öffentliche Eigenschaft (B) innerhalb der Klasse zur Verfügung zu stellen, oder sogar eine alternative Methode mit der gleichen Initialisierung, wenn benötigt?

Dies ist aus Programmierer (nicht subjektiv genug scheinbar) reposted: https://softwareengineering.stackexchange.com/questions/34270/best-methods-for-lazy-initialization-with-properties

+0

@chibacity: Danke für den retag –

Antwort

6

Sie könnten in Erwägung ziehen, die Lazy-Eigenschaften in eine Basisklasse zu verschieben, um direkten Zugriff auf die Hintergrundvariable zu vermeiden. Nicht ideal, ich weiß. Ich habe immer gedacht, dass etwas in C# fehlt, d. H. Direkte Unterstützung für faule Eigenschaften.

+0

Es wäre nett, wenn Sie eine Eigenschaft zuweisen könnten, um es zu veranlassen, all diese Bedürfnisse zu entfernen und implizite Lazy-geladene Eigenschaften zu haben, ohne auf .Value verweisen zu müssen. – BenAlabaster

+0

@BenAlabaster Als ich zum ersten Mal automatische Eigenschaften sah, dachte ich, dass sie faule Fähigkeiten hinzugefügt hatten - leider nicht. Es wäre großartig, eine automatische Eigenschaft mit einer Initialisierungsfunktion definieren zu können. –

+0

@chibacity interessanter Gedanke, ich frage mich, ob das erreichbar wäre ... Zeit zu spielen anfangen;) – BenAlabaster

16

Nun, würde meine empfohlene Lösung Ihrer Mitarbeiter zu sagen, die Eigenschaft zu verwenden, nicht das Feld. Aber man könnte idiotensicher es bis zu einem gewissen Grad wie folgt aus:

public class ClassA 
{ 
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB()); 

    public ClassB B 
    { 
     get 
     { 
      return _b.Value; 
     } 
    } 
} 

Jetzt ist es ziemlich schwer zu vermasseln.

+0

+1. Das war genau das, was ich vorschlagen wollte. –

+0

Was genau ist 'Lazy ' in diesem Beispiel? Vielen Dank. –

+0

Schön, mir war die Lazy Klasse nicht bekannt; Es erscheint jedoch neu in 4, nicht sicher, was das OP verwendet. –

3

@chibacity veröffentlicht (und anschließend) deleted [und später undeleted: P] eine alternative Option, die eine abstrakte Basisklasse verwendet. Obwohl es in Bezug auf die Codeverteilung möglicherweise nicht ideal ist, bietet es eine schöne Kapselung, die eine Menge Code-Clutter-Erzeugung für eine sauberere und prägnantere Klasse A entfernt. Zum Beispiel könnten Sie die Techniken kombiniert betrachten, beide Ziele zu erreichen:

public class ClassB { /* Class to be lazily instantiated */ } 

public abstract class BaseA 
{ 
    private Lazy<ClassB> _b = new Lazy<ClassB>(() => new ClassB()); 
    public virtual ClassB B { get { return _b.Value; } } 
} 

public class ClassA : BaseA 
{ 
    public override ClassB B { get { return base.B; } } 
} 

Auf den ersten Blick scheint es eher wie dieses langatmig ist, aber wenn man das KlasseA betrachten, die die Klasse in dem Sie arbeiten würden und mit, bedeutet dies jetzt, dass alle Ihre Referenzen die gleiche Eigenschaft durchlaufen - es gibt kein unnötiges unnötiges Feld, das potentielle Verwirrung verursacht, es gibt keine direkte Umgehung der Eigenschaft, _b direkt zu referenzieren, und es gibt keine Notwendigkeit, Ihrem Mitarbeiter zu sagen, was zu verwenden ist einziger.

Nicht sagen dies ist der richtige Weg, dies zu tun, oder das ist ein Muster, das sollte oder sollte nicht befolgt werden, ich zeige nur die Vorteile von was @chibacity vorgeschlagen, die sonst unbemerkt bleiben könnten.

Es wäre nett, wenn Sie implizite Lazy-geladene Eigenschaften haben könnten, ohne sich auf B.Value beziehen zu müssen ...zum Beispiel:

[Lazy] 
public ClassB B { get; } 

oder für Objekte ohne parameterlos Konstrukteuren

[Lazy(() => new ClassB("Hello", "World"))] 
public ClassB B { get; } 

oder vielleicht wie vorgeschlagen @chibacity in einem Kommentar

public ClassB B { lazyget; } 

oder

public ClassB B { lazyget : new ClassB(); } 

Ach, ich denke nicht an die se sind derzeit verfügbare lösungen in jeder form ...

+0

Ich mag die Syntax mit dem func und dem Attribut, aber leider müssen Attributargumente kompilierzeitkonstant sein, also ist das out - sieht v. :) –

+0

@chibacity Das ist eine Sache, die mir immer bewusst ist, wenn ich APIs schreibe - wie soll ich die Syntax aussehen lassen, wenn ich sie anrufe oder diese Funktion verwende? Normalerweise entwerfe ich, wie meine Aufrufe aussehen sollen, bevor ich meine API so gestalte, dass alles so ist. – BenAlabaster