C#中的一次性单例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/225686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Disposable singleton in C#
提问by ripper234
I have a singleton that uses the "static readonly T Instance = new T();" pattern. However, I ran into a case where T is disposable, and actually needs to be disposed for unit tests. How can I modify this pattern to support a disposable singleton?
我有一个使用“静态只读 T Instance = new T();”的单例 图案。但是,我遇到了 T 是一次性的情况,实际上需要为单元测试进行处理。如何修改此模式以支持一次性单例?
The interface I would like is something like:
我想要的界面是这样的:
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.
Note - the pattern has to be thread-safe, of course.
注意 - 当然,模式必须是线程安全的。
Edit- for the purpose of production code, this is a true singleton. The thing is that it locks some files, and so for cleanup in unit tests we have to dispose it.
编辑- 出于生产代码的目的,这是一个真正的单例。问题是它锁定了一些文件,因此为了在单元测试中进行清理,我们必须处理它。
I would also prefer a pattern that can be reused, if possible.
如果可能的话,我也更喜欢可以重复使用的模式。
采纳答案by Omer van Kloeten
Mark Release
as internal
and use the InternalsVisibleTo
attribute to expose it only to your unit testing assembly. You can either do that, or if you're wary someone in your own assembly will call it, you can mark it as private
and access it using reflection.
标记Release
为internal
并使用该InternalsVisibleTo
属性仅将其公开给您的单元测试程序集。您可以这样做,或者如果您担心自己程序集中的某个人会调用它,则可以将其标记为private
并使用反射访问它。
Use a finalizer in your singleton that calls the Dispose
method on the singleton instance.
在单例中使用终结器来调用Dispose
单例实例上的方法。
In production code, only the unloading of an AppDomain
will cause the disposal of the singleton. In the testing code, you can initiate a call to Release
yourself.
在生产代码中,只有卸载 anAppDomain
才会导致处理单例。在测试代码中,您可以向Release
自己发起调用。
回答by Jon Skeet
At that point I don't think I'd really consider it to be a singleton any more, to be honest.
到那时,老实说,我认为我不会再认为它是单身人士了。
In particular, if a client uses a singleton they're really not going to expect that they have to dispose of it, and they'd be surprised if someone else did.
特别是,如果客户使用单例,他们真的不会期望他们必须处理它,如果其他人这样做,他们会感到惊讶。
What's your production code going to do?
你的生产代码要做什么?
EDIT: If you really, really need this for unit tests and onlyfor unit tests (which sounds questionable in terms of design, to be frank) then you could always fiddle with the field using reflection. It would be nicer to work out whether it should reallybe a singleton or whether it should reallybe disposable though - the two very rarely go together.
编辑:如果你真的,真的需要这个用于单元测试并且只用于单元测试(坦率地说,这在设计方面听起来有问题)那么你总是可以使用反射来摆弄这个领域。最好弄清楚它是否真的应该是一个单身人士,或者它是否真的应该是一次性的——两者很少在一起。
回答by Bogdan Maxim
You could use a nested lazy singleton (See here) with some simple modifications:
您可以使用嵌套的惰性单例(参见此处)进行一些简单的修改:
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();
}
}
Remember to throw ObjectDisposedException in all public methods/properties of the object if it has been disposed.
如果对象已被释放,请记住在对象的所有公共方法/属性中抛出 ObjectDisposedException。
You should also, provide a finalizer method for the object, in case Dispose doesn't get called. See how to correctly implement IDisposable here.
您还应该为对象提供终结器方法,以防 Dispose 没有被调用。在此处查看如何正确实现 IDisposable 。
回答by Jon Grant
If the class implements IDisposable (as you imply it does) then just call x.Dispose()
如果该类实现 IDisposable(正如您暗示的那样),则只需调用 x.Dispose()
回答by Mark Cidade
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;}
}
回答by Bogdan Maxim
For unit tests you could use a "manual" instance (but you would need a way to instantiate the object).
对于单元测试,您可以使用“手动”实例(但您需要一种方法来实例化对象)。
In your case, probably you should better use the factory pattern (abstract/method - whichever is the best for your case), combined with a singleton.
在您的情况下,您可能应该更好地使用工厂模式(抽象/方法 - 最适合您的情况),并结合单例。
If you want to test if the singleton has disposed properly of the used objects (in unit test), then use the Factory method, otherwise use the singleton pattern.
如果要测试单例是否正确处理了使用的对象(在单元测试中),则使用工厂方法,否则使用单例模式。
By the way, if you don't have access to the singleton source code or you are not allowed to modify it, you would better wrap it to another singleton, and provide all the logic from the new one (more like a proxy). It sounds like overkill, but it could be a viable solution.
顺便说一句,如果您无权访问单例源代码或不允许对其进行修改,则最好将其包装到另一个单例中,并提供新单例的所有逻辑(更像是代理)。这听起来有点矫枉过正,但它可能是一个可行的解决方案。
Also, in order to be able to control the access to it, provide a factory, and let the clients get the new object only if the object hasn't been disposed.
此外,为了能够控制对它的访问,提供一个工厂,并让客户端只有在对象尚未被释放的情况下才能获取新对象。
回答by jezell
Singletons should not be Disposable. Period. If someone calls Dispose prematurely, your application is screwed until it restarts.
单身人士不应该是一次性的。时期。如果有人过早地调用了 Dispose,您的应用程序就会被搞砸,直到它重新启动。
回答by Boris Lipschitz
Another option to make a disposable Singleton is to use SandCastle's [Singleton]atribute for your class, then Castle framework takes care of disposing all disposable Singleton objects
制作一次性单例的另一种选择是为您的类使用 SandCastle 的[Singleton]属性,然后 Castle 框架负责处理所有一次性单例对象