using(SomeClass x = new SomeClass("c:/temp/test.txt"))
{
...
}
在 using 块内,将异常视为正常情况是可以的。但是如果 SomeClass
的构造函数可能会抛出异常怎么办?
using(SomeClass x = new SomeClass("c:/temp/test.txt"))
{
...
}
在 using 块内,将异常视为正常情况是可以的。但是如果 SomeClass
的构造函数可能会抛出异常怎么办?
try
{
using(SomeClass x = new SomeClass("c:/temp/test.txt"))
{
...
}
}
catch(Exception ex)
{
...
}
//Declare object x of type SomeClass.
SomeClass x;
//Instantiate the object by calling the constructor.
x = new SomeClass("c:/temp/test.txt");
try
{
//Do some work on x.
}
finally
{
if(x != null)
x.Dispose();
}
我现在想知道为什么C#设计者没有在try块中包装对象构造,按照我的理解应该这样做。
我想我找到了答案,为什么C#没有将对象构建包装在生成的try块中以代替使用块。
原因很简单。如果你在try块中同时包装声明和实例化,则该对象将超出后面finally块的作用域,代码将无法编译,因为finally块几乎不存在该对象。如果只在try块中包装构造,并在try块之前保留声明,则即使在这种情况下,它也不会编译,因为发现你正在尝试使用已分配的变量。
try
块之前,您可以先将其赋值为null
,然后在try
块内分配真实引用。但也许您不应该这样做,因为如果构造函数未能正确创建对象实例,则它有责任进行清理。 - Leonid Vasilevclass Program
{
static void Main(string[] args)
{
try
{
using (OtherClass inner = new OtherClass())
{
Console.WriteLine("Everything is fine");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.Read();
}
}
class OtherClass : IDisposable
{
public OtherClass()
{
throw new Exception("Some Error!");
}
void IDisposable.Dispose()
{
Console.WriteLine("I've disposed my resources");
}
}
输出:
发生了一些错误!
如果您不抛出异常,那么...
输出:
一切都很好
我已经处理完资源
可能是因为对象从未被创建,所以没有需要调用Dispose。
如果构造函数已经分配了一些资源,并且之后发生了异常,需要进行清理以释放资源,但我不确定会发生什么。
如果一个类被设计得很好,这应该不是问题。记住总体的问题:
public class HoldsResources : IDisposable
{
public HoldsResources()
{
// Maybe grab some resources here
throw new Exception("whoops");
}
}
using (HoldsResources hr = new HoldsResources())
{
}
HoldsResources
构造函数分配的资源?HoldsResources
将持有资源时,就带来了正确释放它们的义务。这意味着在构造函数中使用try/catch/finally块,并且意味着正确实现IDisposable
接口,在Dispose
方法中释放这些资源。using
块调用他的Dispose
方法。仅此而已。当您在构造函数中获取不受垃圾回收管理的资源时,必须确保在出现问题时将其处理掉。
此示例显示了一个构造函数,可以在出现问题时防止泄漏,当您在工厂方法中分配可处理对象时,同样适用相同的规则。
class Sample
{
IDisposable DisposableField;
...
public Sample()
{
var disposable = new SomeDisposableClass();
try
{
DoSomething(disposable);
DisposableField = disposable;
}
catch
{
// you have to dispose of it yourself, because
// the exception will prevent your method/ctor from returning to the caller.
disposable.Dispose();
throw;
}
}
}
编辑:我不得不将我的示例从工厂更改为构造函数,因为显然它并不像我希望的那样容易理解。(根据评论判断。)
当然,这样做的原因是:当您调用工厂或构造函数时,只能处理其结果。当调用进行时,您必须假设到目前为止一切都很好。
调用构造函数或工厂时,您无需进行任何反向心理分析以处理任何无法获取的内容。如果它确实引发异常,则由工厂/构造函数负责在重新抛出异常之前清除任何半分配的内容。 (希望这次足够详细了...)
this.Dispose(true)
(要求Dispose
方法处理部分构造对象)。可行,但有点棘手。我真的希望.NET能更好地处理这个问题。 - supercat