質問

I have the following class to create a 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
}

Then I've created a class 'Person' which is inheriting from this class, thus making it a Singleton.

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
}

And finally, I have my unit test:

    [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.");
    }

My guess is that the unit test should pass, because I asks an instance when the previous one is cleared.

But the person object has the same values as the object had before the ClearInstance() method.

I assumed that this was a safe implementation but it seems that I'm missing something here.

Someone have a clue?

役に立ちましたか?

解決

The reason is that it looks like you have two levels in creating your singleton. Your real singleton is actually the SingletonCreator.instance, and that one never gets cleared.

When Singleton<T> is creating an instance, it calls on SingletonCreator.instance to get the actual instance. When you clear, you clear one from Singleton<T>.instance, but next time you create, it pulls existing one from SingletonCreator.instance which already has an instance that is returned to you.

I don't think you need the extra layer of SingletonCreator. Simply move that code to your Singleton<T> and that'll do it.

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
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top