1

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

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

有没有什么情况我在同一个应用程序中得到两个不同的单例?(带有反射、执行和同步上下文、appdomain 类或任何其他类型的“魔法”的动态 dll 加载?)

4

4 回答 4

3

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

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

Foo foo = (Foo) ctor.Invoke(null);
于 2013-03-02T19:36:19.923 回答
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;

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

在单个 AppDomain 中并且没有任何故意引起问题的事情,你应该没问题。

请注意,无论如何我都不推荐这种单例模式的实现。我通常只使用静态初始化程序来使生活变得更加简单。有关更多详细信息,请参阅我关于单例实现的文章。

于 2013-03-02T19:36:22.343 回答
0

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

private static Foo Instance = new Foo();
于 2013-03-02T19:38:25.317 回答
-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();
    }
于 2021-01-02T18:56:35.520 回答