作为一名 C++ 开发人员,Java 和 .NET 中缺少RAII(资源获取即初始化)一直困扰着我。清理的责任从类编写者转移到其消费者(通过try finally
.NET 的using
构造)这一事实似乎明显逊色。
我明白为什么在 Java 中不支持 RAII,因为所有对象都位于堆上,而垃圾收集器本身不支持确定性销毁,但在 .NET 中引入了值类型(struct
)我们有(似乎) RAII 的完美候选人。在堆栈上创建的值类型具有明确定义的范围,并且可以使用 C++ 析构函数语义。但是,CLR 不允许值类型具有析构函数。
我的随机搜索发现了一个论点,即如果一个值类型被装箱,它就属于垃圾收集器的管辖范围,因此它的销毁变得不确定。我觉得这个论点不够有力,RAII 的好处大到足以说明带有析构函数的值类型不能被装箱(或用作类成员)。
长话短说,我的问题是:是否有任何其他原因不能使用值类型来将 RAII 引入 .NET?(或者你认为我关于 RAII 明显优势的论点有缺陷吗?)
编辑:我一定没有清楚地表达这个问题,因为前四个答案没有抓住重点。我知道它的非确定性Finalize
特征,我知道using
构造,我觉得这两个选项不如 RAII。using
类的消费者还必须记住一件事(有多少人忘记将 aStreamReader
放在一个using
块中?)。我的问题是关于语言设计的哲学问题,为什么它是这样的,可以改进吗?
例如,使用通用的确定性可破坏值类型,我可以使using
andlock
关键字变得多余(可通过库类实现):
public struct Disposer<T> where T : IDisposable
{
T val;
public Disposer(T t) { val = t; }
public T Value { get { return val; } }
~Disposer() // Currently illegal
{
if (val != default(T))
val.Dispose();
}
}
我不禁以我曾经看过但目前无法找到其来源的恰当报价作为结尾。
当我冰冷的死手超出范围时,您可以承担我的确定性破坏。——匿名