Reputation: 5820
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?
Upvotes: 0
Views: 421
Reputation: 4860
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
}
Upvotes: 3