1

Ich habe einen Singleton wie folgt definiert:Bei Verwendung eines Singleton-Musters sollte meine öffentliche Klasse die private oder öffentliche Instanz zurückgeben?

public partial class MoonDataManager 
{ 

    static MoonDataManager _singletonInstance; 
    public static MoonDataManager SingletonInstance 
    { 
     get 
     { 
      return _singletonInstance; 
     } 
     private set 
     { 
      _singletonInstance = value; 
     } 
    } 

Ich habe eine Funktion, die die Instanz sicher erstellt:

public static async Task<MoonDataManager> CreateSingletonAsync() 
    { 
      _singletonInstance = new MoonDataManager(); 

Sollte ich:

return _singletonInstance; (field) 

oder

return SingletonInstance; (property) 

Ich bin besorgt über Garbage Collection, vor allem in iOS oder Android innerhalb von Xamarin.

Auch wenn es in C# Namensmuster gibt, lassen Sie mich wissen, wenn ich von einem Standard abgewichen bin.


Update:

Jetzt denke ich, dass ich mich wirklich mit Threading und asynchroner Methoden stecken geblieben. Hier sind die Objekte und ihre Ziele:

  • MoonDataManager: Führen Sie die RegisterTable<Models.IssuerKey> einmal pro Tisch. Dies ist eine generische Methode, die im Wesentlichen läuft (new MobileServiceSQLiteStore).DefineTable<T>()

  • OfflineStore: Dies ist ein MobileServiceSQLiteStore.

  • MobileClient: Dies ist ein MobileServiceClient.

  • MoonDataManager Abhängigkeiten: Der MoonDataManager benötigt OfflineStore und MobileClient, um die Initialisierung zu beenden. Insbesondere tut es ein MobileServiceClient .SyncContext.InitializeAsync (OfflineStore)

Ich bin nicht sicher, wie Sinn dieser Spaghetti von Abhängigkeiten zu machen ... oder wie Sie den Code machen schön aussehen und sicher Thread .

Hier ist die neue Iteration des Codes:

private readonly Lazy<MobileServiceClient> lazyMobileClient = 
     new Lazy<MobileServiceClient>(() => new MobileServiceClient(Constants.ApplicationURL), true); // true for thread safety 
    public MobileServiceClient MobileClient { get { return lazyMobileClient.Value; } } 


    private readonly Lazy< MobileServiceSQLiteStore> offlineDB = 
     new Lazy<MobileServiceSQLiteStore>(() => new MobileServiceSQLiteStore(Constants.OfflineDBName), true); // true for thread safety 
    private MobileServiceSQLiteStore OfflineStore { get { return offlineDB.Value; } } 

    private static readonly Lazy<MoonDataManager> lazy = new Lazy<MoonDataManager>(() => new MoonDataManager(), true); // true for thread safety 
    public static MoonDataManager Instance { get { return lazy.Value; } } 

    private MoonDataManager() 
    { 

      MoonDataManager.Instance.RegisterTable<Models.IssuerKey>(); 

      // Initialize file sync 
      // todo: investigate FileSyncTriggerFactory overload. 
      //Was present on Mar 30, 2016 Channel9 https://channel9.msdn.com/events/Build/2016/P408 
      MoonDataManager.Instance.MobileClient.InitializeFileSyncContext 
          (new IssuerKeyFileSyncHandler(Instance), Instance.OfflineStore); 

      // NOTE THE ASYNC METHOD HERE (won't compile) 
      await MoonDataManager.Instance.MobileClient 
           .SyncContext.InitializeAsync(MoonDataManager.Instance.OfflineStore, 
           StoreTrackingOptions.NotifyLocalAndServerOperations); 

    } 
+1

FYI Es ist nicht threadsicher wie Sie es haben. Lesen Sie [dies] (http://csharpindepth.com/Articles/General/Singleton.aspx) – CodingYoshi

+0

FYI - Ich experimentiere auch mit diesem Ansatz: https://forums.xamarin.com/discussion/25881/using-async -in-xamarin-forms (Kommentar von rene_ruupert) – LamonteCristo

Antwort

0

Sie sollten die private Instanz zurück. Sie können mehr über das Singleton-Muster auf MSDN lesen. Die Standard-Singleton-Implementierung lautet wie folgt:

public class Singleton 
{ 
    private static Singleton instance; 

    private Singleton() {} 

    public static Singleton Instance 
    { 
     get 
     { 
      if (instance == null) 
      { 
      instance = new Singleton(); 
      } 
      return instance; 
     } 
    } 
} 

Normalerweise haben Sie keinen Setter für die Eigenschaft. Dieses Muster hat already previously been discussed on SO.

+1

Dies ist kein threadsafe, nur ein fyi – CodingYoshi

+0

True @CodingYoshi. Wenn Multithreading eine Rolle spielt, sollte eine 'Sperre' verwendet werden. Dieses Muster wird auch in dem Link beschrieben, den ich von MSDN angehängt habe. Aber die Frage beschrieb diese Besorgnis nicht, also unterließ ich die Tatsache. – Demitrian

+0

Aus welchem ​​Grund wurde dies abgelehnt? Es beantwortet die Frage vollkommen in Ordnung. – Demitrian

3

Die Definition

static MoonDataManager _singletonInstance; 

stellt sicher, dass die Instanz von MoonDataManager eine GC Wurzel ist, und es wird erst, wenn die Anwendungsdomäne endet gesammelt werden, because it is a static value.


Ich würde das private Singleton zurückgeben und auf die Auto-Eigenschaft verzichten, die Sie haben.

public partial class MoonDataManager 
{ 
    private static readonly Lazy<MoonDataManager> _manager = 
     new Lazy<MoonDataManager>(() => new MoonDataManager()); 

    public static MoonDataManager SingletonInstance => _manager.Value; 
} 

MoonDataManager.Value Wenn zum ersten Mal zugegriffen wird, initialisiert wird, um die Func<MoonDataManager> verwenden, die für Lazy<T> an den Konstruktor übergeben wurde. Bei nachfolgenden Zugriffen wird dieselbe Instanz zurückgegeben.

+0

Ich habe gerade meinen Code in der Frage aktualisiert und dies erweitert. – LamonteCristo

3

A Singleton schafft sich das erste Mal zugegriffen wird, in einer Weise, dass nur eine Instanz gewährleistet werden erstellt, auch wenn ein zweiter Thread versucht, darauf zuzugreifen, während es noch

Ihre CreateSingletonAsync() instanziiert wird ist gegen diese und sieht aus wie es

für Multi-Thread-Bösartigkeit erlauben würde

Sie wollen so etwas wie:

public static MoonDataManager SingletonInstance 
{ 
    get 
    { 
     if (_singletonInsatnce != null) 
      return _singletonInstance; 
     lock (lockobject) 
     { 
      // check for null again, as new one may have been created while a thread was waiting on the lock 
      if (_singletonInsatnce != null) 
       return _singletonInstance; 
      else 
       // create new one here. 
     } 
    } 
    // no setter, because by definition no other class can instantiate the singleton 
} 

das ist alles nur, um sicherzustellen, dass zwei Threads für ein Objekt zu fragen am Ende nicht zwei Objekte erstellen , oder der zweiter Thread erhält ein halb erstelltes Objekt, wenn der erste Thread noch erstellt wird.

Hinweis: Singletons sind unmodern geworden.

Hinweis: Wenn Sie sicher sein können, dass Sie Zeit haben, Ihr Objekt vor dem Zugriff zu erstellen, können Sie einfach ein statisches Element verwenden und es beim Start der Anwendung erstellen.

Ihre Frage "sollte ich die Eigenschaft oder das Feld zurückgeben" macht keinen Sinn - Sie geben das Feld bereits vom Property Getter zurück, was gängige Praxis ist. Wo sonst möchtest du etwas zurückgeben?

+0

Wie kann ich das nutzen, wenn der Singleton 'ctor' Async-Methoden enthält? Was ist eine bessere Alternative zu einem Singleton? – LamonteCristo

+0

Ich habe gerade meinen Code in der Frage aktualisiert und diesen erweitert. – LamonteCristo

5

Für .NET 4 oder höher können Sie Lazy<T> verwenden und es so erstellen.

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton(), true); // true for thread safety 

    public static Singleton Instance { get { return lazy.Value; } } 

    private Singleton() 
    { 
    } 
} 

Es wird nur dann erstellt werden, wenn auf sie zugegriffen wird und nur das erste Mal, und es ist THREAD.

+0

Wie kann ich das nutzen, wenn der Singleton 'ctor' Async-Methoden enthält? – LamonteCristo

+0

Ich habe gerade meinen Code in der Frage aktualisiert und diesen erweitert. – LamonteCristo

Verwandte Themen