我有以下通用单例提供程序的代码实现:
public sealed class Singleton<T> where T : class, new()
{
Singleton()
{
}
public static T Instance
{
get { return SingletonCreator.instance; }
}
class SingletonCreator
{
static SingletonCreator()
{
}
internal static readonly T instance = new T();
}
}
这个样本来自2篇文章,我合并了代码以获得我想要的东西:
http://www.yoda.arachsys.com/csharp/singleton.html和 http://www.codeproject.com/Articles/11111/Generic-Singleton-Provider
这就是我尝试使用上述代码的方式:
public class MyClass
{
public static IMyInterface Initialize()
{
if (Singleton<IMyInterface>.Instance == null // Error 1
{
Singleton<IMyInterface>.Instance = CreateEngineInstance(); // Error 2
Singleton<IMyInterface>.Instance.Initialize();
}
return Singleton<IMyInterface>.Instance;
}
}
界面:
public interface IMyInterface
{
}
Error 1
的错误是:
'MyProject.IMyInterace' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MyProject.Singleton<T>'
Error 2
的错误是:
Property or indexer 'MyProject.Singleton<MyProject.IMyInterface>.Instance' cannot be assigned to -- it is read only
如何解决这个问题,使其符合上述2篇文章?任何其他想法或建议表示赞赏。
我的实现是否打破了Singleton模式?
答案 0 :(得分:2)
当然,那里有一个问题。你通用是假设采取类,而不是接口。
internal static readonly T instance = new T();
您的代码假设要创建该类的实例,您无法实例化接口类型。
所以,如果你需要某种类型作为单音,你应该写:
Singleton<MyInterface>.Instance
其中
public class MyInterface : IMyInterface { }
然后你不需要任何&#39;如果&#39;在你的代码中,因为Singleton负责即时对象并将其保持为只有一个实例。
与问题无关:目前Singletone被许多开发人员视为“代码嗅觉”,所以一般情况下你必须避免使用它们。试着在没有Singletone的情况下考虑申请。
答案 1 :(得分:2)
基本上,你已经在你的单例类上给出了一个类约束,以及new()约束。
写作时
Singleton<IMyInterface>
您使用的接口类型为T,这违反了您定义的类型约束。
对于错误2,
Singleton<IMyInterface>.Instance = CreateEngineInstance();
您正在尝试将值分配给只读属性。因此,您需要在Instance属性上定义一个setter,以使该行生效。
<强>更新强>
这些方面应该为你做的事情:
public sealed class Singleton
{
private static Hashtable bindings = new Hashtable();
private static Hashtable instances = new Hashtable();
private static void checkType(Type requested, Type bound)
{
if (requested.IsValueType)
throw new Exception("Cannot bind a value type to a reference type");
// also check type inheritance and other things...
}
private static void checkBinding(Type requested)
{
if (!(bindings.ContainsKey(requested)))
throw new Exception(String.Format("Type {0} was not bound !", requested.FullName));
}
public static void Bind<T, U>() where U : class, new()
{
checkType(typeof(T), typeof(U));
bindings[typeof(T)] = typeof(U);
}
public static T GetInstance<T>()
{
Type requested = typeof(T);
Type bound = (Type) bindings[requested];
checkBinding(requested);
if (!instances.ContainsKey(requested)) {
// We know that type "bound" was set with a new() class constraint
instances[requested] = (T) Activator.CreateInstance(bound);
}
return (T) instances[requested];
}
}
然后你可以写:
Singleton.Bind<IMyInterface, MyClass>();
IMyInterface instance = Singleton.GetInstance<IMyInterface>();
如果您想要更进一步,您还可以指定此提供程序创建的对象的生命周期,以便您可以使用单例,或让提供程序为每个调用返回一个新对象,依此类推。
您还应该看一下依赖注入模式,它似乎与您想要实现的模式接近,并且还要查看已经完成此操作的现有DI框架(NInject,Nhibernate)以及更多内容。