如果我考虑单例的基本实现,例如:
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类,或任何其他类型的“魔术”?)
答案 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;
foo1
和foo2
都将是非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();
}