我可以用这种方式为所有派生的单身人士定义一个抽象类吗?

这是我的抽象类,每次我想创建一个Singleton时都必须派生它:

public abstract class Singleton where T : Singleton { private static readonly Lazy _instance = new Lazy(() => { var constructor = typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null); return (T)constructor.Invoke(null); }); public static T Instance { get { return _instance.Value; } } public Singleton() { } } 

所以,每次我需要遵循Singleton设计模式时,我可以这样做:

 sealed class Server : Singleton { private Server() { } ... } 

这是完全正确的,如果没有,为什么?

编辑:

  • 在派生类示例上添加了私有构造函数并在抽象基础上调用。

编辑:

  • 重写类型参数初始化。

自我实现的单身人士是一种反模式。 如果你只是实现一个工厂,那么inheritance并将你的类锁定为特定forms的需要就会消失:

 public class Server {} //Not coupled to any inheritance hierarchy. public class Factory { private readonly Lazy _server = new Lazy(() => new Server()); public Server Server { get { return _server.Value; } } } 

但是,您实际上将工厂用作服务定位器,并且服务定位器也被视为反模式,因为您可以轻松地使用DI将Server实例注入到消费类中。

 public class MyServerConsumer { public MyServerConsumer(Server server) { //Do stuff. } } 

温莎风格注册:

  ... Component.For(); ... 

注意单词singleton从未被提及过? 您仍然可以获得“对象的单个实例”,但您不必编写代码来维护该关系,并且您的类从一开始就不受“单例”概念的约束和破坏

不,你不能,因为当你想要使用new T()你应该有一个公共构造函数,它与单例定义不同。 因为在单例中你应该有一个私有构造函数,在这种情况下(公共一个),每个人都可以创建对象的新实例,而不是单例。

您正在使用的这种方法具有明显的缺点。 您将您的课程结合到Singleton课程。 除了通常不是SOLID之外,您将失去从您可能需要的类派生的能力(如果该类不是Singleton)。

最佳实践是您需要使用dependency injection和IoC容器。 所有IoC容器都允许您指定类是否为Singleton的天气。

这样,类完全无视它被实例化为Singleton的事实,并且很容易在不改变依赖性的情况下即时更改它。

C#不保证何时创建静态字段_instance 。 这是因为C#标准只是声明类(在IL中标记为BeforeFieldInit)可以在访问字段之前的任何时间初始化其静态字段。 这意味着它们可能在第一次使用时被初始化,它们可能在之前的某个时间初始化,您无法确定何时。

删除懒惰用法

我建议删除Lazy构造并引入静态ctor来创建实例。 这样你就可以利用C#标准的BeforeFieldInit ,但是你会失去懒惰。 虽然它在某种程度上是懒惰的,但它不是在使用类型之前创建的。 这很好,因为无论如何都会使用大多数单身人士。

 public abstract class Singleton where T : class, new() { private static readonly T _instance; public static T Instance { get { return _instance; } } public static Singleton() { _instance = new T(); } } 

公共问题

你现在遇到的问题是new T()构造迫使你有一个公共ctor。 这对单身人士来说并不是很好。 您可以使用通过reflection调用的私有ctor来解决此问题。

这只是对pjvds回复的评论(我无法以常规方式发表评论,因为我没有足够的分数……)。

您可以使用私有init方法,而不是通过reflection使用私有构造函数,并在静态Singlton方法中的“new T()”之后调用它。