1

If I consider the basic implementation of the singleton, for example:

private static Foo instance;
private readonly static Object SyncRoot=new Object();

public static Foo Instance {
    get {
        if(instance!=null)
            return instance;

        lock(SyncRoot) {
            if(instance!=null) {
                return instance;
            }

            instance=new Foo();
            return instance;
        }
    }
}

Is there any situation I get two different singletons in the same application? (dynamic dll load with reflection, execution and syncronization context's, appdomain class, or any other type of "magic"?)

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
J. Lennon
  • 3,311
  • 4
  • 33
  • 64

4 Answers4

3

Yes, it's possible with reflection, your code only applies to the property, reflection can create Foo instance without the property.

ConstructorInfo ctor = typeof(Foo).GetConstructors
        (BindingFlags.Instance | BindingFlags.NonPublic)[0];

Foo foo = (Foo) ctor.Invoke(null);
gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Ooh, I hadn't even thought of calling the (presumably private) constructor by reflection. I went for setting the field back to null - see my answer for sample code. – Jon Skeet Mar 02 '13 at 19:40
  • It may seem strange, but if I load/call the same assembly of two different filepath. With the same class, it throws me for two singleton (even using the Instance property) – J. Lennon Mar 02 '13 at 22:24
  • @J.Lennon. Why do you use reflection at all? can't use have a reference to the assembly? – gdoron Mar 02 '13 at 22:26
  • @gdoron the class that will use my singleton is dynamically loaded (because of the abstraction/internface) and I need simulate the behavior of the code without change a original application – J. Lennon Mar 02 '13 at 22:34
3

You'd have to define what you meant by "the same application". If one "application" can span multiple AppDomains, then yes - each AppDomain would effectively have a completely separate Foo class. Likewise if you've got trusted code using reflection to reset the instance field to null, you'd end up with two instances very easily:

var field = typeof(Foo).GetField("instance",
                                 BindingFlags.Static | BindingFlags.NonPublic);

var foo1 = Foo.Instance;
field.SetValue(null, null);
var foo2 = Foo.Instance;

foo1 and foo2 will both be non-null, different references. Or as gdoron's answer mentioned, the code could just call the (presumably private) constructor by reflection too.

Within a single AppDomain and without anything deliberately causing problems, you should be fine.

Note that I wouldn't recommend this implementation of the singleton pattern anyway though. I typically just use static initializers to make life significantly simpler. See my article on singleton implementations for more details.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • it's even easier with reflection, isn't? – gdoron Mar 02 '13 at 19:37
  • @gdoron: Yup, was just editing for that. Now provided sample code. – Jon Skeet Mar 02 '13 at 19:37
  • HaHa, very nice, setting `instance` to null... but it's easier to simply call the ctor. +1. – gdoron Mar 02 '13 at 19:43
  • @JonSkeet thanks for your reply! But I have a problem, my application is with 2 singletons, this happens when I received a first call from the WCF service (same application), some hint of why this is happening? – J. Lennon Mar 02 '13 at 20:22
  • @J.Lennon: Can you reproduce this every time? Add some logging within the singleton constructor - including the stack trace - to work out what's going on. – Jon Skeet Mar 02 '13 at 20:28
  • @JonSkeet Well, I found the problem. This is shameful, I was loading/calling property with reflection, but the file contained in the class with the implementation was pointing the other filepath (Assembly.LoadFrom), the incredible is that this was not throwing any exception, the file was loaded and normally called, but was not the "original Singleton" – J. Lennon Mar 02 '13 at 22:21
  • @J.Lennon: Ah, that makes sense. No reason it would throw an exception - it's just another type in another assembly... – Jon Skeet Mar 02 '13 at 22:26
  • @JonSkeet Even with the same name, signature, version..? That does not seem right to me, but ok, I understand. – J. Lennon Mar 02 '13 at 22:28
  • 2
    @J.Lennon: Yup - because if two types are in different assemblies, they're simply different types. – Jon Skeet Mar 02 '13 at 22:30
0

Certainly if you use different AppDomains then you will get one instance per AppDomain. I think there may also be problems with the locking mechanism you are using if you are in a multi-thread environment. Instead of creating the instance in the getter use

private static Foo Instance = new Foo();
Brian O''Byrne
  • 550
  • 2
  • 10
-1

Reflection resistant Singleton pattern:

public sealed class Singleton
{
    public static Singleton Instance => _lazy.Value;
    private static Lazy<Singleton, Func<int>> _lazy { get; }

    static Singleton()
    {
        var i = 0;
        _lazy = new Lazy<Singleton, Func<int>>(() =>
        {
            i++;
            return new Singleton();
        }, ()=>i);
    }

    private Singleton()
    {
        if (_lazy.Metadata() == 0 || _lazy.IsValueCreated) 
            throw new Exception("Singleton creation exception");
    }

    public void Run()
    {
        Console.WriteLine("Singleton called");
    }
}

then try it:

    static void Main(string[] args)
    {
        Singleton.Instance.Run();

        ((Singleton) Activator.CreateInstance(typeof(Singleton), true)).Run();
    }
robert
  • 49
  • 3