C#中的一次性单身人士

我有一个使用“静态只读T实例=新T();”的单例 图案。 但是,我遇到了T是一次性的情况,实际上需要处理以进行unit testing。 如何修改此模式以支持一次性单件?

我想要的界面是这样的:

var x = Foo.Instance; var y = Foo.Instance; // x == y ... x.Release(); // this causes the next Foo.Instance to return a fresh object // also, it assumes no further operations on x/y will be performed. 

注意 – 模式当然必须是线程安全的。

编辑 – 出于生产代码的目的,这是一个真正的单身人士。 问题是它锁定了一些文件,因此在unit testing中我们必须处理它。

如果可能的话,我也更喜欢可以重复使用的模式。

Mark Release as internal并使用InternalsVisibleTo属性将其仅显示给您的unit testing程序集。 您可以这样做,或者如果您在自己的程序集中有人会小心地调用它,您可以将其标记为private并使用reflection访问它。

在单例中使用终结器,在单例实例上调用Dispose方法。

在生产代码中,只有卸载AppDomain才会导致处理单例。 在测试代​​码中,您可以发起自己Release的调用。

在那一点上,我不认为我真的认为它不再是一个单身人士,说实话。

特别是,如果一个客户使用单身人士,他们真的不会指望他们必须处理它,如果其他人这样做,他们会感到惊讶。

你的生产代码要做什么?

编辑:如果你真的,真的需要这个unit testing, 用于unit testing(这在设计方面听起来有问题,坦白说),那么你总是可以使用reflection来调整字段。 如果它真的应该是一个单身人士,或者它是否真的应该是一次性的,那就更好了 – 两者很少一起去。

单身人士不应该是一次性的。 期。 如果有人过早地调用Dispose,那么您的应用程序将被重置,直到它重新启动。

  public class Foo : IDisposable { [ThreadStatic] static Foo _instance = null; private Foo() {IsReleased = false;} public static Foo Instance { get { if (_instance == null) _instance = new Foo(); return _instance; } } public void Release() { IsReleased = true; Foo._instance = null; } void IDisposable.Dispose() { Release(); } public bool IsReleased { get; private set;} } 

如果该类实现了IDisposable(正如你所暗示的那样),那么只需调用x.Dispose()

你可以使用嵌套的懒惰单例(见这里 )进行一些简单的修改:

 public sealed class Singleton : IDisposable { Singleton() { } public static Singleton Instance { get { if (!Nested.released) return Nested.instance; else throw new ObjectDisposedException(); } } public void Dispose() { disposed = true; // Do release stuff here } private bool disposed = false; class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } } 

记住在对象的所有公共方法/属性中抛出ObjectDisposedException(如果已经处置)。

您还应该为对象提供终结器方法,以防Dispose被调用。 在此处了解如何正确实现IDisposable。

对于unit testing,您可以使用“手动”实例(但您需要一种实例化对象的方法)。

在您的情况下,您可能应该更好地使用工厂模式(抽象/方法 – 最适合您的情况),并结合单例。

如果要测试单例是否已正确处理所使用的对象(在unit testing中),则使用Factory方法,否则使用单例模式。

顺便说一句,如果您无法访问单例源代码或者不允许对其进行修改,则最好将其包装到另一个单例中,并提供新代码中的所有逻辑(更像是代理)。 这听起来有点矫枉过正,但它可能是一个可行的解决方案。

此外,为了能够控制对它的访问,提供工厂,并且只有在尚未处理对象时才让客户端获取新对象。

制作一次性Singleton的另一个选择是为您的类使用SandCastle的[Singleton]属性,然后Castle框架负责处理所有一次性Singleton对象