C# 如何使IDisposable对象成为类变量?
我正在使用C#处理Active Directory。实例化C# 如何使IDisposable对象成为类变量?,c#,active-directory,idisposable,class-variables,C#,Active Directory,Idisposable,Class Variables,我正在使用C#处理Active Directory。实例化PrincipalContext对象似乎很昂贵,因此我想将其存储在类变量中 当使用PrincipalContext作为局部变量时,我可以使用方便的使用语法。在静态变量中存储IDisposable对象时,如何确保正确处理该对象?通常的模式是在类上实现IDisposable接口。举个例子: public class YourClass : IDisposable { private OtherDisposableType yourRe
PrincipalContext
对象似乎很昂贵,因此我想将其存储在类变量中
当使用
PrincipalContext
作为局部变量时,我可以使用方便的使用
语法。在静态变量中存储IDisposable
对象时,如何确保正确处理该对象?通常的模式是在类上实现IDisposable
接口。举个例子:
public class YourClass : IDisposable
{
private OtherDisposableType yourResource;
public YourClass()
{
yourResource = new OtherDisposableType();
}
public void Dispose()
{
yourResource.Dispose();
}
}
这至少是你需要做的
编辑
我以前的版本主张在所有情况下都遵循终结器模式,这被(正确地)指出是违反框架设计准则的。但是,在实际处理非托管资源的情况下(例如,进行直接的P/Invoke调用并获取需要显式释放的句柄)建议您创建一个终结器,并在其中调用Dispose
,以防有人使用您的代码而不调用Dispose
:
public class YourClass : IDisposable
{
private OtherDisposableType yourResource;
public YourClass()
{
yourResource = new OtherDisposableType();
}
public void Dispose()
{
yourResource.Dispose();
GC.SuppressFinalize(this);
}
~YourClass()
{
Dispose();
}
}
因此,基本上您希望缓存一个昂贵的资源。这是件好事 全局数据(在这种情况下是静态变量)不是一件好事,IMHO。相反,为什么不将其作为实例变量并控制其生存期呢 编写处理广告职责的类,让它创建和使用PrincipalContext,并使其也可IDisposable(使用)。从中提取一个接口以使其解耦,并使使用它的类更易于测试
想要使用AD服务的类将采用新接口(或DI)的构造函数参数。您可以在using块中手动创建类并将其传递给类,也可以使用。您可以让框架将AD对象的生存期设置为容器的生存期(也可以是IDisposable)。有关这方面的更多信息,请参阅和您的DI容器文档。查看
System.ComponentModel
命名空间的作用。基本上,我通常使用的模式是拥有一个子组件集合,其中包括我拥有的所有不是“值”的东西——无论它是否实现了IDisposable
然后,当我自己Dispose()
时,我迭代这个集合并Dispose
实现IDisposable
的任何东西
这种技术的一个优点是,如果我拥有的对象一开始不是一次性的,但后来添加了IDisposable
接口,那么我的类将在不必更改的情况下做正确的事情
此外,使用DI/IoC容器可以为您解决大部分问题。您希望何时处置它?好问题我在想当类型是垃圾收集的时候。当GC检测到内存中的对象没有留下对该类型实例的引用时,可能会发生这种情况?@Ben:不要依赖GC来处理对象。任何实现IDisposable的对象都必须被决定性地处理掉,否则它将无法实现接口。GC收集是动态的,永远不会保证发生。有些CLR类型永远不会被GC收集。如果您不
Dispose
它们,它们将一直存在于您的应用程序中,直到关闭为止,无论对象是否引用它们。@kyoryu-出于兴趣,您能给我一个这样的CLR类型的示例吗?非常感谢,但是当实例符合GC条件时,不会调用析构函数吗,我希望我的静态变量在实例间保持不变?@Ben:我不推荐使用静态变量。如果您强烈认为需要这样做,那么唯一的方法就是在类上添加一个静态Dispose
方法,在应用程序关闭时(或在任何适当的时间)显式调用该方法。它一开始就很好。但在建议实现终结器后,情况变得越来越糟。删除它,你会得到一个很好的答案。实际上,Microsoft建议不要创建终结器,除非你处理的是非托管资源。即使这样,您通常也可以通过使用像SafeHandle这样的包装来避免它。有关详细信息,请参阅《框架设计指南》一书中有关Dispose模式的部分。您不应该从终结器中调用其他对象-它们自己可能已经被终结了!如果对象正在包装一些必须完全释放的非托管资源,那么它已经有了自己的终结器。我非常喜欢这个答案,谢谢。产生的讨论在我脑海中留下了一个学术问题,即如何最好地处理存储在类变量中的IDisposable类型的处理(这可能是由于我的理解不足)。@Ben-谢谢!我同意我们还没有回答这个问题(尽管Adam Robinson关于静态Dispose方法的评论值得考虑)。我倾向于将静态/类变量(除了字符串和正则表达式之类的只读不可变变量)视为代码气味,类似于其他语言中的全局变量。关于这一点的有趣讨论:不完全是我所说的——不一定是一次性集合,而是存储在集合中的对象的任何子组件(不管是哪种类型的)。一次性收集的想法听起来有点吓人,尽管我现在还不太清楚为什么。