Gra*_*amS 28 .net c# dispose idisposable
如果我有一个SomeDisposableObject实现的类IDisposable:
class SomeDisposableObject : IDisposable
{
public void Dispose()
{
// Do some important disposal work.
}
}
Run Code Online (Sandbox Code Playgroud)
我有另一个叫做的类AContainer,它有SomeDisposableObject一个公共属性的实例:
class AContainer
{
SomeDisposableObject m_someObject = new SomeDisposableObject();
public SomeDisposableObject SomeObject
{
get { return m_someObject; }
set { m_someObject = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后FxCop将坚持AContainer也是IDisposable.
这是很好的,但我看不出我可以安全地调用m_someObject.Dispose()从AContainer.Dispose(),作为另一个类可能还是要在一个参考m_someObject实例.
避免这种情况的最佳方法是什么?
(假设其他代码依赖于AContainer.SomeObject始终具有非空值,因此只是将实例的创建移到外部AContainer不是一个选项)
编辑:我将扩展一些例子,因为我认为一些评论者错过了这个问题.如果我只实现一个调用m_someObject.Dispose()的Dispose()方法,AContainer那么我将留下这些情况:
// Example One
AContainer container1 = new AContainer();
SomeDisposableObject obj1 = container1.SomeObject;
container1.Dispose();
obj1.DoSomething(); // BAD because obj1 has been disposed by container1.
// Example Two
AContainer container2 = new AContainer();
SomeObject obj2 = new SomeObject();
container2.SomeObject = obj2; // BAD because the previous value of SomeObject not disposed.
container2.Dispose();
obj2.DoSomething(); // BAD because obj2 has been disposed by container2, which doesn't really "own" it anyway.
Run Code Online (Sandbox Code Playgroud)
这有帮助吗?
Joe*_*Joe 24
没有一个答案,这取决于你的情况,关键点是财产所代表的可支配资源的所有权,正如Jon Skeet指出的那样.
查看.NET Framework中的示例有时很有帮助.以下是三个表现不同的示例:
容器总是处置.System.IO.StreamReader公开一次性属性BaseStream.它被认为拥有底层流,并且处理StreamReader始终处理底层流.
容器永远不会丢弃.System.DirectoryServices.DirectoryEntry公开Parent属性.它不被认为拥有其父级,因此处理DirectoryEntry永远不会释放其父级.
在这种情况下,每次取消引用Parent属性时都会返回一个新的DirectoryEntry实例,并且可能需要调用者处理它.可以说这打破了属性的准则,也许应该有一个GetParent()方法.
容器有时处理.System.Data.SqlClient.SqlDataReader公开一次性Connection属性,但调用者使用SqlCommand.ExecuteReader的CommandBehavior参数决定读者是否拥有(并因此处置)底层连接.
另一个有趣的例子是System.DirectoryServices.DirectorySearcher,它具有读/写一次性属性SearchRoot.如果从外部设置此属性,则假定基础资源不属于该属性,因此容器不会处置该属性.如果它不是从外部设置的,则在内部生成引用,并设置一个标志以确保它将被丢弃.你可以用Lutz Reflector看到这个.
您需要确定容器是否拥有该资源,并确保准确记录其行为.
如果您确定拥有该资源,并且该属性是可读/写的,则需要确保您的setter处理它正在替换的任何引用,例如:
public SomeDisposableObject SomeObject
{
get { return m_someObject; }
set
{
if ((m_someObject != null) &&
(!object.ReferenceEquals(m_someObject, value))
{
m_someObject.Dispose();
}
m_someObject = value;
}
}
private SomeDisposableObject m_someObject;
Run Code Online (Sandbox Code Playgroud)
更新:GrahamS在评论中正确地指出在处置之前最好在setter中测试m_someObject!= value:我已经更新了上面的例子以考虑到这一点(使用ReferenceEquals而不是!=显式).虽然在许多现实场景中,setter的存在可能意味着该对象不归容器所有,因此不会被处置.
Jon*_*eet 14
这实际上取决于谁在理论上"拥有"一次性物品.在某些情况下,您可能希望能够传入对象,例如在构造函数中,而不会让您的类负责清理它.其他时候你可能想要自己清理它.如果您正在创建对象(如示例代码中所示),那么清理它几乎肯定是您的责任.
至于财产 - 我不认为拥有财产应该真正转移所有权或类似的东西.如果您的类型负责处理对象,则应该保留该责任.
真正的问题可能是您的面向对象设计.如果AContainer是Disposed,则也应该处理其所有成员对象.如果不是这听起来像你可以处置一个身体但想要保持腿部实例生活.听起来不对劲.
| 归档时间: |
|
| 查看次数: |
5914 次 |
| 最近记录: |