首页 > 解决方案 > 在单例类的 get 实例属性中使用 setter 是否是一种好习惯

问题描述

在单例类中,在某个时间点,我需要处理实例并清理类及其成员。当然我不能使用IDispossible界面。使用特定实例完成后,setter在属性中使用 a 并分配 null 是一种好习惯吗?GetInstance或者从singleton类中公开一个静态函数以明确清除现有实例?

标签: c#propertiessingletongetter-setter

解决方案


TL;博士:

如果您需要释放非托管资源 - 我们将使用的场景IDisposable,那么实现IDisposable并且不要使该类成为单例。

如果您没有非托管资源并且您需要单例,请将其设为单例,而不必担心“setter”将事物设置为空。这不是必需的。


您正在尝试完成两件事:使一个类一次性并使其成为一个单例,并且您已经看到两者不能很好地结合在一起。我不会IDisposable放弃并寻找一种不同的方式来释放托管资源,而是相反。实现IDisposable但不要使该类成为单例。

为什么?主要是因为通常有其他方法可以强制只存在一个类的一个实例而不使其成为单例。例如,大多数依赖注入容器,包括IServiceProvider,都可以很容易地将依赖注册为单例:

services.AddSingleton<ThingThatIOnlyWantOneOf>();

这并不意味着它ThingThatIOnlyWantOneOf实际上是一个单例。我们可以创建它的多个实例。我们只是表明我们只想创建一个实例,然后一遍又一遍地使用它。

即使我们不使用任何 IoC/DI 容器,我们仍然可以限制我们创建的类的实例数量,而无需实际使其成为单例。(如果/当我们意识到我们确实需要更多实例时,这使我们可以灵活地改变主意。)

现在如何将类编写为单例并使类一次性的问题已经消失了。我们正在使用不同的方法来创建和重用该类的一个实例,并且该类可以是一次性的。


还值得注意的是,将某些内容设置为 null 与实施IDisposable.

我们通常不会在处理完对象引用后将其设置为 null,因为 .NET Framework 会为我们处理这些。当不再引用对象时,对象会超出范围,然后垃圾收集器将其从内存中删除。所有这一切都可以在我们不做任何事情的情况下有效地发生。这就是为什么在将对象设置为 null 的方法末尾看不到额外的代码行的原因。

我们只IDisposable在类处理非托管资源时才实现——例如,SQL 连接或打开的文件流。这些类实际上必须做一些事情来释放它们的资源,我们希望它尽快发生。

这意味着如果某些东西确实需要是一次性的,那么仅仅将其设置为 null 并不能实现这一点。我们想实际调用Dispose(). 如果它实际上不需要是一次性的,那么我们无论如何都不需要将它设置为 null。我们可以让它超出范围并收集垃圾。

因此,如果您担心需要“清除”某些内容或将某些内容设置为 null,那么您可能不需要。IDisposable存在以标记需要“清理”的事物。这是一种知道如果某些东西没有实现,那么我们就不需要担心它的方式。(否则,出于怀疑和不确定性,我们会四处将所有内容设置为 null,这不会那么有趣。)


推荐阅读