Diese Klasse ermöglicht es ein Objekt erst dann zu erstellen, wenn man das Objekt wirklich braucht.
Das bedeutet, dass sich das Verhalten des Codes den Laufzeitbedingungen anpasst.
Dies ist vor allem dann nützlich, wenn der Konstruktor des Objektes sehr rechenintensiv oder speicherintensiv ist.
Die Verwendung des Codes ist ganz einfach, es gibt zwei Möglichkeiten:
// Erstellt eine RLazyInit-Instanz für ein Objekt mit einem Konstruktor ohne Parameter
RLazyInit<Te> v = RLazyInit<Te>.Create<Te>();
// Erstellt eine RLazyInit-Instanz für ein Objekt mit einem Konstruktor mit Parametern.
RLazyInit<Te> v2 = new RLazyInit<Te>(() => { return new Te("Hallo Welt", 9, ...) });
Sobald man das Objekt mittels
Value erfragt, wird es erst erstellt.
Dies kann in vielen Situationen sehr
praktisch sein:
1. Einfaches erstellen einer statischen Variable mit Wert.
// Dieses Beispiel funktioniert ohne RLazyInit und ist sehr umfangreich...
private static MyObject _current = null;
public static MyObject Current {
get {
if(_current == null) {
_current = new MyObject();
}
return _current;
}
}
Hingegen kann man das auch in nur einer Zeile Code erledigen:
public static RLazyInit Current = RLazyInit.Create();
2. Das Objekt erst erstellen, wenn es auch notwendig ist.
Dies ermöglicht es, die Parameter an den Konstruktor bereits zu übergeben, ohne das Objekt an der Stelle direkt zu starten.
Man kann so z.B. das Objekt im Haupt-Thread erstellen und die Parameter von der UI auslesen und dann das Objekt mit dem Konstruktor
in einen zweiten Thread auslagern und erst dort bei Bedarf erstellen.
Update [30.06.2015]: Informationen auf Antwort von @Jan Welker hierher kopiert.
//
// Die Funktion, die das Objekt vom Type @T erstellen sollte.
//
public delegate T RLazyInitFunc<T>();
//
// Ermöglicht die verzögerte Initialisation eines Objektes.
// Dies kann sehr praktisch sein, wenn der Construktor() sehr langsam arbeitet,
// das Objekt aber jetzt erstellt werden muss ohne auf den ctor() zu warten.
// Das Objekt wird erst erstellt, wenn über @Value auf dieses Zugegriffen wird.
//
public sealed class RLazyInit<T>
{
private readonly T _nullValue;
private T m_value;
private RLazyInitFunc<T> m_func;
public RLazyInit(RLazyInitFunc<T> f)
{
m_func = f;
_nullValue = default(T);
m_value = _nullValue;
}
public T Value {
get {
if (!HasValue) {
m_value = m_func();
}
return m_value;
}
}
// Gibt an, ob das Objekt bereits erstellt wurde.
public bool HasValue {
get {
return !_Equal(m_value, _nullValue);
}
}
//
// Erstellt eine standart RLazyInit-Instanz,
// die erwartet, dass der Type einen ctor() ohne Paramter hat.
// Dieser wird dann auch verwendet beim Erstellen.
//
public static RLazyInit<TV> Create<TV>() where TV : new() {
return new RLazyInit<TV>(() => {
return new TV();
});
}
private static bool _Equal(T a, T b) {
return Object.Equals(a, b);
}
}