我有一个类,其中一个IDisposable
成员变量在线初始化,另一个IDisposable
在构造函数中。
如果构造函数抛出,会调用Dispose()
吗?如果是这样,那么我认为null
检查是必要的......?如果没有,那么内嵌成员如何处置?
sealed class SomeDisposable : IDisposable { ... }
sealed class Foo : IDisposable
{
readonly SomeDisposable sd1= new SomeDisposable(); // this doesn't throw
readonly SomeDisposable sd2;
public Foo()
{
sd2 = new SomeDisposable(); // assume this throws
// how does sd1 get Dispose()d?
}
public void Dispose()
{
sd1.Dispose();
if (sd2!= null) // is this null check necessary?
sd2.Dispose();
}
}
答案 0 :(得分:1)
目前C#中没有办法使用内联初始化程序安全地初始化IDisposable
,除非通过涉及ThreadStatic
变量的讨厌的黑客攻击。必须通过工厂方法调用构造函数,该方法创建一个dispos-manager对象并将引用存储在线程静态字段中。然后,字段初始化程序可以将它们的值包装在静态方法的调用中,该方法将它们添加到dispos-manager对象中。
实际的字段初始化程序语法最终非常合理:
DisposalManager Cleaner = DisposalManager.CurrentManager;
DType1 DField1 = DisposalManager.Guard(new DType1);
DType2 DField2 = DisposalManager.Guard(new DType2);
Dispose
清理也是如此:
void Dispose(bool disposing)
{
Cleaner.Cleanup(disposing);
}
不幸的是,需要每次调用Guard
自己访问线程静态字段,并且让所有构造函数调用都包含在工厂方法中,这使构造变得相当丑陋。太糟糕了,因为能够使用单行声明,创建和清理字段比在代码中的三个不同位置执行这些操作要好得多。
答案 1 :(得分:0)
让我们假设您在表单中使用以下代码:
var foo = new Foo(someByteArray);
您的构造函数抛出异常,然后foo
将为null,因为类构造函数未完成。任何试图调用Dispose
的尝试都会导致NRE发生。
答案 2 :(得分:0)
有趣的问题。
试过这个:
try
{
//caller
using (var x = new Disposable1()) { }
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
public class Disposable1 : IDisposable
{
private Disposable2 first = new Disposable2();
private Disposable2 second;
public Disposable1()
{
second = new Disposable2("Goodbye!");
}
public void Dispose()
{
Debug.WriteLine("Disposable1.Dispose()");
first.Dispose();
if (second != null)
second.Dispose();
}
}
public class Disposable2 : IDisposable
{
public string Whatever { get; set; }
public Disposable2() { Whatever = "Hello!"; }
public Disposable2(string whatever)
{
Whatever = whatever;
throw new Exception("Doh!");
}
public void Dispose()
{
Debug.WriteLine("Disposable2.Dispose()" + Whatever);
}
}
......而且输出是......
Doh!
所以似乎没有成员被初始化或处置。