使用单例模式时,我的公共类应该返回私有还是公共实例?

时间:2017-01-02 23:20:11

标签: c# xamarin.ios garbage-collection xamarin.android automatic-ref-counting

我有一个单身定义如下:

public partial class MoonDataManager
{

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

我有一个安全地创建实例的函数:

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

我应该:

return  _singletonInstance;  (field) 

return SingletonInstance;  (property)

我关注垃圾收集,特别是在Xamarin的iOS或Android中。

如果在C#中有这样的命名模式,请告诉我是否偏离了标准。

更新:

现在我觉得自己真的陷入了线程和异步方法的困境。以下是对象及其目标:

  • MoonDataManager:每张桌子运行一次RegisterTable<Models.IssuerKey>。这是一种基本上运行(new MobileServiceSQLiteStore).DefineTable<T>()

  • 的通用方法
  • OfflineStore:这是MobileServiceSQLiteStore

  • MobileClient:这是MobileServiceClient

  • MoonDataManager依赖关系:MoonDataManager要求OfflineStore和MobileClient完成初始化。具体来说,它执行MobileServiceClient。SyncContext.InitializeAsync(OfflineStore

我不确定如何理解这种依赖关系的意义......或者如何使代码看起来更好,并且是线程安全的。

以下是代码的新迭代:

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);

    }

4 个答案:

答案 0 :(得分:5)

对于.NET 4或更高版本,您可以使用Lazy<T>并像这样创建它。

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()
    {
    }
}

只有在第一次访问并且它是线程安全时才会创建它。

答案 1 :(得分:3)

定义

static MoonDataManager _singletonInstance;

确保MoonDataManager的实例是GC根,并且在应用程序域结束后才会收集because it is a static value

我将返回私人单身人士并放弃你拥有的自动财产。

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

    public static MoonDataManager SingletonInstance => _manager.Value; 
}

首次访问MoonDataManager.Value时,会使用传递给Func<MoonDataManager>的构造函数的Lazy<T>对其进行初始化。在后续访问中,返回相同的实例。

答案 2 :(得分:3)

Singleton在第一次访问时创建自己,确保只创建一个实例,即使第二个线程在仍然被实例化时尝试访问它也是如此

你的CreateSingletonAsync()违反了这一点,看起来它允许多线程的肮脏

你想要这样的东西:

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
}

所有这些只是为了确保请求一个对象的两个线程不会最终创建两个对象,或者如果第一个线程的一个仍然被创建,则第二个线程获得一个半创建的对象。

注意:单身人士变得不合时宜。

注意:如果您确定在访问对象之前有时间创建对象,则可以使用静态成员并在应用程序启动时创建它。

你的问题“我应该归还属性或字段”没有意义 - 你已经从属性getter返回字段,这是标准做法。还有什么地方想要归还什么?

答案 3 :(得分:0)

您应该返回私有实例。您可以在MSDN上阅读有关单例模式的更多信息。标准单例实现如下:

public class Singleton
{
    private static Singleton instance;

    private Singleton() {}

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

虽然,通常情况下,您没有该物业的设定者。此模式具有already previously been discussed on SO