Vra

Met ander woorde, is hierdie Singleton implementering draad veilig:

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}
Was dit nuttig?

Oplossing

Static vervaardigerskampioenskap is gewaarborg om slegs een keer uitgevoer word per aansoek domein, voordat enige gevalle van 'n klas geskep word of enige statiese lede aangevra. http://msdn.microsoft.com/en-us/library/aa645612.aspx

Die getoon implementering veilig is vir die aanvanklike konstruksie draad, dit is, geen sluiting of nul toetsing word vereis vir die bou van die Singleton voorwerp. Dit beteken egter nie dat enige gebruik van die instansie sal gesinchroniseer word. Daar is 'n verskeidenheid van maniere waarop dit gedoen kan word; Ek het getoon een hieronder.

public class Singleton
{
    private static Singleton instance;
    // Added a static mutex for synchronising use of instance.
    private static System.Threading.Mutex mutex;
    private Singleton() { }
    static Singleton()
    {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
    }

    public static Singleton Acquire()
    {
        mutex.WaitOne();
        return instance;
    }

    // Each call to Acquire() requires a call to Release()
    public static void Release()
    {
        mutex.ReleaseMutex();
    }
}

Ander wenke

Terwyl al hierdie antwoorde gee dieselfde algemene antwoord, daar is een caveat.

Onthou dat alle potensiële afleidings van 'n generiese klas is saamgestel as individuele tipes. Wees dus versigtig wanneer die uitvoering van statiese vervaardigerskampioenskap vir generiese tipes.

class MyObject<T>
{
    static MyObject() 
    {
       //this code will get executed for each T.
    }
}

EDIT:

Hier is die demonstrasie:

static void Main(string[] args)
{
    var obj = new Foo<object>();
    var obj2 = new Foo<string>();
}

public class Foo<T>
{
    static Foo()
    {
         System.Diagnostics.Debug.WriteLine(String.Format("Hit {0}", typeof(T).ToString()));        
    }
}

In die konsole:

Hit System.Object
Hit System.String

Die gebruik van 'n statiese constructor eintlik is threadsafe. Die statiese konstruktor is gewaarborg om slegs een keer uitgevoer word.

Van die C # taalspesifikasie http: // MSDN. microsoft.com/en-us/library/aa645612(VS.71).aspx :

  

Die statiese constructor vir 'n klas voer op die meeste een keer in 'n gegewe aansoek domein. Die uitvoering van 'n statiese constructor word veroorsaak deur die eerste van die volgende gebeure om plaas te vind in 'n aansoek domein:

     
      
  • 'n geval van die klas geskep word.
  •   
  • Enige van die statiese lede van die klas is gekla.
  •   

So ja, jy kan vertrou dat jou Singleton korrek sal aangehaal.

Zooba het 'n uitstekende punt (en 15 sekondes voor my, ook!) Wat die statiese constructor nie waarborg draad-veilige gedeelde toegang tot die Singleton. Wat benodig in 'n ander wyse hanteer moet word.

Hier is die Cliffnotes weergawe van die bogenoemde MSDN bladsy op c # Singleton:

Gebruik die volgende patroon, altyd, jy kan nie verkeerd gaan:

public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}

Bo en behalwe die voor die hand liggend Singleton funksies, dit gee jou hierdie twee dinge vir gratis (ten opsigte van Singleton in C ++):

  1. lui konstruksie (of geen konstruksie asof dit nooit genoem)
  2. sinchronisasie

Static vervaardigerskampioenskap is gewaarborg om te brand net een keer per App Domain so jou benadering OK moet wees. Dit is egter funksioneel geen verskil tussen die meer bondige, inline weergawe:

private static readonly Singleton instance = new Singleton();

Thread veiligheid is meer van 'n probleem as jy lui is initialiseren dinge.

Die Common Language Infrastructure spesifikasie waarborg dat " 'n tipe inisialiseerder sal net een keer te hardloop vir enige gegewe tipe, tensy dit uitdruklik genoem deur die gebruiker-kode. " (Artikel 9.5.3.1.) So, tensy jy 'n paar vreemdsoortig IL op die los roeping Singleton ::. Cctor direk (onwaarskynlik) jou statiese constructor sal loop presies een keer voor die Singleton tipe gebruik word, sal slegs een voorbeeld van Singleton geskep sal word, en jou aanleg eiendom is draad-veilige.

Let daarop dat indien constructor Singleton se toegang tot die eiendom aanleg (selfs indirek) dan die eiendom aanleg sal nul wees. Die beste wat jy kan doen is op te spoor wanneer dit gebeur en gooi 'n uitsondering, deur te kyk wat byvoorbeeld is nie-nul in die eiendom accessor. Na jou statiese constructor voltooi sal die eiendom aanleg nie-nul wees.

As antwoord Zoomba se wys daarop sal jy nodig het om te Singleton veilig om toegang vanaf verskeie drade te maak, of te implementeer 'n sluitmeganisme rondom die gebruik van die Singleton byvoorbeeld.

Die statiese constructor sal Voltooi loop voor is 'n draad toegelaat om toegang te verkry tot die klas.

    private class InitializerTest
    {
        static private int _x;
        static public string Status()
        {
            return "_x = " + _x;
        }
        static InitializerTest()
        {
            System.Diagnostics.Debug.WriteLine("InitializerTest() starting.");
            _x = 1;
            Thread.Sleep(3000);
            _x = 2;
            System.Diagnostics.Debug.WriteLine("InitializerTest() finished.");
        }
    }

    private void ClassInitializerInThread()
    {
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() starting.");
        string status = InitializerTest.Status();
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() status = " + status);
    }

    private void classInitializerButton_Click(object sender, EventArgs e)
    {
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
    }

Die kode hierbo geproduseer die resultate hieronder.

10: ClassInitializerInThread() starting.
11: ClassInitializerInThread() starting.
12: ClassInitializerInThread() starting.
InitializerTest() starting.
InitializerTest() finished.
11: ClassInitializerInThread() status = _x = 2
The thread 0x2650 has exited with code 0 (0x0).
10: ClassInitializerInThread() status = _x = 2
The thread 0x1f50 has exited with code 0 (0x0).
12: ClassInitializerInThread() status = _x = 2
The thread 0x73c has exited with code 0 (0x0).

Hoewel die statiese konstruktor het 'n lang tyd om te hardloop, die ander drade gestop en gewag. Alle drade lees die waarde van _x stel aan die onderkant van die statiese constructor.

Net om pedanties wees nie, maar daar is nie so iets soos 'n statiese konstruktor, maar eerder statiese tipe initializers, hier is 'n klein demo van sikliese statiese constructor afhanklikheid wat hierdie punt illustreer.

Static constructor gewaarborg word ryg veilig. Ook, check die bespreking oor Singleton by DeveloperZen: http: //www.developerzen com / 2007/07/15 / whats-verkeerd-met-die-kode-1-bespreking /

Hoewel ander antwoorde is meestal korrek, daar is nog 'n caveat met statiese vervaardigerskampioenskap.

As per afdeling II.10.5.3.3 Races en dooie van die ECMA-335 gemeenskaplike taal infrastruktuur

  

Tik inisialisering alleen sal 'n dooiepunt, tensy 'n kode nie skep   genoem van 'n tipe inisialiseerder (direk of indirek) uitdruklik   roep blokkeer bedrywighede.

Die volgende kode resultate in 'n dooiepunt

using System.Threading;
class MyClass
{
    static void Main() { /* Won’t run... the static constructor deadlocks */  }

    static MyClass()
    {
        Thread thread = new Thread(arg => { });
        thread.Start();
        thread.Join();
    }
}

Oorspronklike skrywer is Igor Ostrovsky, sien sy pos hier .

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top