我一直在寻找一种方法来确保在所有情况下都清理类的成员变量,例如类构造函数末尾的异常。
因为它们是成员变量,所以“try、catch”和“using”模式没有用处。我注意到 .NET C++ (C++ /clr:safe) 提供了智能指针(称为 msclr::auto_handle)的模拟,例如 auto_ptr 或 shared_ptr。这非常有用,因为我可以以非常干净的方式对有限资源(例如线程或套接字)进行确定性销毁。
我一直在分析使用 C++ /clr 生成的 IL,并注意到它实际上似乎所做的只是在修改封装数据的每个函数中使用 try/faults 向 IL 发送垃圾邮件。
我已经为任何感兴趣的人提供了 IL 列表。(try/fault 不是我添加的,是 C++/clr 编译器添加的)
MyClass()
{
myDisposable.reset(gcnew MyDisposable());
throw gcnew Exception("Hello World");
// myDisposable needs to clean up now
// because it is very large or locks a limited resource.
// Luckily with RAII.. it does!
}
……变成……
.try
{
IL_0006: ldarg.0
IL_0007: ldloc.0
IL_0008: stfld class msclr.'auto_handle<MyDisposable>' modreq([mscorlib]System.Runtime.CompilerServices.IsByValue) MyClass::myDisposable
IL_000d: ldarg.0
IL_000e: call instance void [mscorlib]System.Object::.ctor()
IL_0013: ldarg.0
IL_0014: ldfld class msclr.'auto_handle<MyDisposable>' modreq([mscorlib]System.Runtime.CompilerServices.IsByValue) MyClass::myDisposable
IL_0019: newobj instance void MyDisposable::.ctor()
IL_001e: call instance void msclr.'auto_handle<MyDisposable>'::reset(class MyDisposable)
IL_0023: ldstr "Hello World"
IL_0028: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_002d: throw
IL_002e: leave.s IL_003c
} // end .try
fault
{
IL_0030: ldarg.0
IL_0031: ldfld class msclr.'auto_handle<MyDisposable>' modreq([mscorlib]System.Runtime.CompilerServices.IsByValue) MyClass::myDisposable
IL_0036: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003b: endfinally
} // end handler
是否有类似的方法可以使用 C# 实现这一点,因为我的软件将非常复杂,而且我自己处理这一切将非常危险且容易出错。那么有没有人知道可以自动添加这个额外的 IL 代码以便我可以用 C# 模拟 RAII 的技术甚至构建后步骤?
编辑:(另一个例子)
ref class MyClass
{
private:
msclr::auto_handle<MyDisposable> myDisposable;
public:
MyClass()
{
myDisposable.reset(gcnew MyDisposable());
throw gcnew Exception("Hello World");
// myDisposable needs to clean up now because it is very large or locks a limited resource.
}
};
myDisposable 是一个成员变量。当从构造函数中抛出“Hello World”时,myDisposable 实际上会立即被释放。我可以在 C# 中获得相同的功能吗?我们已经确认 using 无法工作,因为它位于成员变量上,并且每个函数中的 try/catch 是一个非常糟糕的解决方案。
此致,
卡斯滕