有没有任何情况我在同一个应用程序中得到两个不同的单身人士?

时间:2013-03-02 19:33:20

标签: c# singleton

如果我考虑单例的基本实现,例如:

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

是否有任何情况我在同一个应用程序中获得两个不同的单身人士? (动态DLL加载反射,执行和同步上下文,appdomain类,或任何其他类型的“魔术”?)

4 个答案:

答案 0 :(得分:3)

是的,可以通过反射,您的代码仅适用于该属性,反射可以创建没有该属性的Foo实例。

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

Foo foo = (Foo) ctor.Invoke(null);

答案 1 :(得分:3)

你必须定义“同一个应用程序”的含义。如果一个“应用程序”可以跨多个AppDomain,那么是 - 每个AppDomain实际上都有一个完全独立的Foo类。同样,如果您使用反射将可信代码重置为instance字段为null,那么您最终会轻松获得两个实例:

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

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

foo1foo2都将是非null,不同的引用。或者正如gdoron的回答所提到的,代码也可以通过反射来调用(可能是私有的)构造函数。

在一个AppDomain中,没有任何故意导致问题,你应该没问题。

请注意,我不会推荐单例模式的这种实现。我通常只使用静态初始化器来简化生活。有关详细信息,请参阅我的article on singleton implementations

答案 2 :(得分:0)

当然,如果您使用不同的AppDomain,那么每个AppDomain将获得一个实例。 我认为如果您处于多线程环境中,您使用的锁定机制可能也存在问题。 而不是在getter中使用

创建实例
private static Foo Instance = new Foo();

答案 3 :(得分:-1)

抗反射单例模式:

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

那就试试吧:

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

        ((Singleton) Activator.CreateInstance(typeof(Singleton), true)).Run();
    }