将IDisposable传递到父IDisposable时的结果是什么?
昨天,在我们的代码库上运行Visual Studio代码分析后,以下代码突出显示为一个问题:
using (var stringReader = new StringReader(someString)) { using (var reader = XmlReader.Create(stringReader)) { // Code } }
返回的警告是
警告CA2202对象’stringReader’可以在方法’(方法名称)’中多次处理。 为避免生成System.ObjectDisposedException,不应在对象上多次调用Dispose。
在搜索堆栈溢出之后,我得出一般的理解,如果我要创建一个包含IDisposable成员的自定义类,它应该实现IDisposable本身,并调用该成员的dispose()
方法。
我的两个问题是
假设对象X将取Y的所有权并且从那时开始,调用X.dispose()将始终导致调用Y.dispose()是正确的
不,假设它永远不会保存。 让我们检查一下这个特例: XmlReader.Create(Stream)
。
在参考源中找到相当多的代码后,我发现Dispose
方法调用Close
方法。 这很明显。 然后注意这段代码 :
public override void Close() { Close( closeInput ); }
因此,后备流是否将被关闭和处置取决于设置closeInput
的值,您可以通过XmlReaderSettings.CloseInput
设置来设置该值。
所以这里的答案是肯定的:你不能确定它是被处置的。 你应该总是确保自己。
顺便说一句, MSDN说:
方法实现包含可能导致在同一对象上多次调用IDisposable.Dispose或Dispose等效项(如某些类型的Close()方法)的代码路径。
因此, Close()
方法调用的路径也可以生成此警告,这就是您在案例中看到此警告的原因。
在对象X在创建过程中引用IDisposable对象Y作为参数的所有情况下,假设对象X将获得Y的所有权并且从该点开始是正确的,调用X.dispose()将始终导致调用Y.dispose()
我想不是,我会试着解释原因。
有一种名为IDisposablePattern的模式,它看起来像这样:
public class SimpleClass : IDisposable { // managed resources SqlConnection implements IDisposable as well. private SqlConnection _connection; private bool _disposed; // implementing IDisposable public void Dispose() { // Here in original Dispose method we call protected method with parameter true, // saying that this object is being disposed. this.Dispose(true); // Then we "tell" garbage collector to suppress finalizer for this object because we are releasing // its memory and doesnt need to be finalized. Calling finalizer(destructor) of a given type is expensive // and tweaks like this help us improve performance of the application. GC.SuppressFinalize(this); } // Following the best practices we should create another method in the class // with parameter saying whether or not the object is being disposed. // Its really important that this method DOES NOT throw exceptions thus allowing to be called multiple times protected virtual void Dispose(bool disposing) { // another thing we may add is flag that tells us if object is disposed already // and use it here if (_disposed) { return; } if (_connection != null) { _connection.Dispose(); _connection = null; } _disposed = true; // call base Dispose(flag) method if we are using hierarchy. } }
请注意,当您的类使用非托管资源时,可以将其扩展到新级别:
上述就是C#学习教程:将IDisposable传递到父IDisposable时的结果是什么?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
public class SimpleClass2: IDisposable { // managed resources private SqlConnection _connection; private bool _disposed; // unmanaged resources private IntPtr _unmanagedResources; // simple method for the demo public string GetDate() { // One good practice that .NET Framework implies is that when object is being disposed // trying to work with its resources should throw ObjectDisposedException so.. if(_disposed) { throw new ObjectDisposedException(this.GetType().Name);} if (_connection == null) { _connection = new SqlConnection("Server=.\SQLEXPRESS;Database=master;Integrated Security=SSPI;App=IDisposablePattern"); _connection.Open(); } // allocation of unmanaged resources for the sake of demo. if (_unmanagedResources == IntPtr.Zero) { _unmanagedResources = Marshal.AllocHGlobal(100 * 1024 * 1024); } using (var command = _connection.CreateCommand()) { command.CommandText = "SELECT getdate()"; return command.ExecuteScalar().ToString(); } } public void Dispose() { // Here in original Dispose method we call protected method with parameter true, // saying that this object is being disposed. this.Dispose(true); // Then we "tell" garbage collector to suppress finalizer for this object because we are releasing // its memory and doesnt need to be finalized. Calling finalizer(destructor) of a given type is expensive // and tweaks like this help us improve performance of the application. // This is only when your class doesnt have unmanaged resources!!! // Since this is just made to be a demo I will leave it there, but this contradicts with our defined finalizer. GC.SuppressFinalize(this); } // Following the best practices we should create another method in the class // with parameter saying wether or not the object is being disposed. // Its really important that this method DOES NOT throw exceptions thus allowing to be called multiple times protected virtual void Dispose(bool disposing) { // another thing we may add is flag that tells us if object is disposed already // and use it here if (_disposed) { return; } // Thus Dispose method CAN NOT release UNMANAGED resources such as IntPtr structure, // flag is also helping us know whether we are disposing managed or unmanaged resources if (disposing) { if (_connection != null) { _connection.Dispose(); _connection = null; } _disposed = true; } // Why do we need to do that? // If consumer of this class forgets to call its Dispose method ( simply by not using the object in "using" statement // Nevertheless garbage collector will fire eventually and it will invoke Dispose method whats the problem with that is if we didn't // have the following code unmanaged resources wouldnt be disposed , because as we know GC cant release unmanaged code. // So thats why we need destructor(finalizer). if (_unmanagedResources != IntPtr.Zero) { Marshal.FreeHGlobal(_unmanagedResources); _unmanagedResources = IntPtr.Zero;; } // call base Dispose(flag) method if we are using hierarchy. } ~DatabaseStateImpr() { // At this point GC called our finalizer method , meaning // that we don't know what state our managed resources are (collected or not) because // our consumer may not used our object properly(not in using statement) so thats why // we skip unmanaged resources as they may have been finalized themselves and we cant guarantee that we can // access them - Remember? No exceptions in Dispose methods. Dispose(false); } }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1019578.html