Feedback

C# - Singleton Basisklasse (thread-safe, generic, Lazy Creation)

Veröffentlicht von am 22.11.2009
(2 Bewertungen)
Eine Basisklasse die eine einheitliche und thread-sichere Schnittstelle für Singleton(http://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)) bietet. Implementiert wurde die Basisklasse in der "Lazy Creation"-Variation(http://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)#Lazy_Creation).

Da die Basisklasse die Ableitungen nicht mit new instanziiert, wird zusätzlich eine Init-Methode bereitgestellt um das Singleton zu intialisieren (muss überschrieben werden). Ebenfalls ist es möglich (sofern benötigt) dass eine Methode "Refresh", bei wiederholtem anfordern der einmaligen Instanz, aufgerufen wird. Hat jedoch ebenfalls nur Auswirkung wenn diese Methode "Refresh" auch in der Ableitung überschrieben wird.

Erforderliche Using:

using System;
using System.Runtime.Serialization;
/// <summary>
/// This class provide a generic and thread-safe interface for Singleton classes.
/// </summary>
/// <typeparam name="T">The specialized singleton which is derived
/// from SingletonBase&lt;T&gt;</typeparam>
public abstract class SingletonBase<T>
  where T : SingletonBase<T>
{
  /* the lock object */
  private static object _lock = new object();

  /* the static instance */
  private static T _instance = null;
  /// <summary>
  /// Get the unique instance of <typeparamref name="T"/>.
  /// This property is thread-safe!
  /// </summary>
  public static T Instance
  {
    get
    {
      if (_instance == null)
      {
        lock (_lock)
        {
          if (_instance == null)
          {
            /* Create a object without to use new (where you need a public ctor) */
            object obj = FormatterServices.GetUninitializedObject(typeof(T));
            if (obj != null)  // just 4 safety, but i think obj == null shouldn't be possible
            {
              /* an extra test of the correct type is redundant,
               * because we have an uninitialised object of type == typeof(T) */
              _instance = obj as T;
              _instance.Init(); // now the singleton will be initialized
            }
          }
        }
      }
      else
      {
        _instance.Refresh();  // has only effect if overridden in sub class
      }
      return _instance;
    }
  }

  /// <summary>
  /// Called while instantiation of singleton sub-class.
  /// This could be used to set some default stuff in the singleton.
  /// </summary>
  protected virtual void Init()
  { }

  /// <summary>
  /// If overridden this will called on every request of the Instance but
  /// the instance was already created. Refresh will not called during
  /// the first instantiation, for this will call Init.
  /// </summary>
  protected virtual void Refresh()
  { }
}

// usage:
class SingletonTest
  : SingletonBase<SingletonTest>
{
  ~SingletonTest()
  { Console.WriteLine("~SingletonTest called ..."); }

  public void DoSomething()
  { Console.WriteLine("SingletonTest::DoSomething called ..."); }

  public void DoAnother()
  { Console.WriteLine("SingletonTest::DoAnother called ..."); }

  protected override void Init()
  { Console.WriteLine("SingletonTest::Init called ..."); }

  protected override void Refresh()
  { Console.WriteLine("SingletonTest::Refresh called ..."); }
}

public class Program
{
  public static void Main(string[] args)
  {
    SingletonTest.Instance.DoSomething();
    SingletonTest.Instance.DoAnother();

    Console.WriteLine("press any key ...");
    Console.ReadKey(true);
  }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!