我有一个使用“静态读取t实例= new t();”的单例。图案。然而,我遇到了 T 是一次性的情况,并且实际上需要进行单元测试的处理。如何修改此模式以支持一次性单例?

我想要的界面是这样的:

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.

注意 - 当然,该模式必须是线程安全的。

编辑 - 就生产代码而言,这是真正的单例。问题是它锁定了一些文件,因此为了在单元测试中进行清理,我们必须处理它。

如果可能的话,我还希望有一个可以重复使用的模式。

有帮助吗?

解决方案

标记 Release 作为 internal 并使用 InternalsVisibleTo 属性以仅将其公开给您的单元测试程序集。您可以这样做,或者如果您担心自己的程序集中有人会调用它,您可以将其标记为 private 并使用反射访问它。

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

在生产代码中,仅卸载 AppDomain 将导致单例的处置。在测试代​​码中,您可以发起调用 Release 你自己。

其他提示

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

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

您的生产代码要做什么?

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

单身人士不应该是一次性的。期。如果有人过早地调用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 此处

对于单元测试,您可以使用“手册”。实例(但你需要一种实例化对象的方法)。

在你的情况下,你应该更好地使用工厂模式(抽象/方法 - 最适合你的情况),结合单身人士。

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top