Singleton工厂(基类)不“清除”实例

时间:2014-05-12 18:19:30

标签: c# singleton

我有以下课程来创建一个Singelton:

public class Singleton<T> where T : class
{
    #region Constructors

    protected Singleton()
    { }

    #endregion Constructors

    #region Properties

    private static T instance;

    public static T GetInstance()
    {
        if (instance == null)
        { instance = SingletonCreator.Singleton; }

        return instance;
    }

    public static void ClearInstance()
    { instance = null; }

    #endregion Properties

    #region Inner classes

    private class SingletonCreator
    {
        #region Properties

        private static readonly T instance = typeof(T).InvokeMember(typeof(T).Name,
            BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null, null, null, CultureInfo.CurrentCulture) as T;

        internal static T Singleton
        { get { return instance; } }

        #endregion Properties
    }

    #endregion Inner classes
}

然后我创建了一个班级&#39; Person&#39;它继承自这个类,从而使它成为一个单身人士。

public class Person : Singleton<Person>
{
    #region Constructors

    protected Person() { }

    #endregion

    #region Properties

    public string Firstname { get; set; }

    public string Name { get; set; }

    public int Age { get; set; }

    #endregion
}

最后,我进行了单元测试:

    [TestMethod]
    public void then_the_new_instance_should_have_default_values_for_the_properties()
    {
        Person.GetInstance().Age = 1;
        Person.GetInstance().Name = "Unit";
        Person.GetInstance().Firstname = "Test";

        Person.ClearInstance();
        Assert.AreEqual(Person.GetInstance().Age, 0, "The age property of the requested instance is incorrect.");
        Assert.AreEqual(Person.GetInstance().Name, "", "The name property of the requested instance is incorrect.");
        Assert.AreEqual(Person.GetInstance().Firstname, "", "The firstname property of the requested instance is incorrect.");
    }

我的猜测是单元测试应该通过,因为我在清除前一个实例时会询问一个实例。

但是person对象与ClearInstance()方法之前的对象具有相同的值。

我认为这是一个安全的实现,但似乎我在这里遗漏了一些东西。

有人有线索吗?

1 个答案:

答案 0 :(得分:3)

原因是你在创建单身时看起来有两个层次。你的真正的单身实际上是SingletonCreator.instance,而且那个永远不会被清除。

Singleton<T>创建实例时,它会调用SingletonCreator.instance来获取实际实例。当您清除时,从Singleton<T>.instance清除一个,但是下次创建时,它会从已经有一个返回给您的实例的SingletonCreator.instance中提取现有的一个。

我认为你不需要额外的SingletonCreator层。只需将该代码移至您的Singleton<T>即可。

public class Singleton<T> where T : class
{
    #region Constructors

    protected Singleton()
    { }

    #endregion Constructors

    #region Properties

    private static readonly object instanceLock = new object();
    private static T instance;

    public static T GetInstance()
    {
        if (instance == null)
        {
            lock(instanceLock)
            {
                if (instance == null)
                {
                    instance = typeof(T).InvokeMember(typeof(T).Name,
            BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null, null, null, CultureInfo.CurrentCulture) as T; 
                }
            }
        }

        return instance;
    }

    public static void ClearInstance()
    { instance = null; }

    #endregion Properties
}