C# 变量声明、初始化和无管理内存分配后的清理

C# 变量声明、初始化和无管理内存分配后的清理,c#,.net,C#,.net,当涉及到定义变量、为变量分配空间、初始化变量以及正确清理所有内容时,我想请教您关于c#良好编程实践的建议 我目前面临的问题是,我有一个使用非托管API函数的函数,因此也会访问非托管内存(使用封送处理)。在退出之前,我希望将功能清理干净并妥善处理所有内容。但问题是,所有实际工作都是在try-catch块中完成的。这意味着我不能在一次捕获或最后阻塞中清理所有东西 我所做的是声明所有变量,为它们保留内存,并在进入函数后立即初始化它们,然后清除finally块中的所有内容(关闭句柄,释放内存,…) 这一

当涉及到定义变量、为变量分配空间、初始化变量以及正确清理所有内容时,我想请教您关于c#良好编程实践的建议

我目前面临的问题是,我有一个使用非托管API函数的函数,因此也会访问非托管内存(使用封送处理)。在退出之前,我希望将功能清理干净并妥善处理所有内容。但问题是,所有实际工作都是在try-catch块中完成的。这意味着我不能在一次捕获或最后阻塞中清理所有东西

我所做的是声明所有变量,为它们保留内存,并在进入函数后立即初始化它们,然后清除finally块中的所有内容(关闭句柄,释放内存,…)

这一切都很好,但我也希望在try块中完成变量声明、初始化和内存分配(例如,在初始化数组或在内存中分配空间时,也可能出错,天知道在哪里)。我想到的唯一一件事就是在两个try-catch块上筑巢。这样行吗,还是你会提出其他建议

以下是我到目前为止的情况:

//Declare variables, allocate memory, initialize variables.
........
try
{
    //Do actual work - write to file and read from a file in my case
    .........
}
catch (Exception exc)
{
    //Exception handler for file write/read errors
}
finally
{
    //Clean up (release handles, free memory,...)
}
以下是我的想法:

try
{
   //Declare variables, allocate memory, initialize variables.
   ........
   try
   {
       //Do actual work - write to file and read from a file in my case
       .........
   }
   catch (Exception exc)
   {
       //Exception handler for file write/read errors
   }
}
catch (Exception exc_1)
{
    //Exception handler for variable declaration, initialization, memory allocation errors
}
finally
{
    //Clean up (release handles, free memory,...)
}
提前感谢您的帮助


干杯

您可以实现
IDisposable
接口来调用Dispose方法

或者作为最佳实践,使用block
使用

using (var variable = .....)
{

 ...

}
使用block的特殊性在于在处理结束时调用Dispose方法

例如,如果使用
SqlConnection

var(var connection = new SqlConnection("...."))
{
....

}
仅此代码就足够了

链接:


链接:

该方法的问题是变量超出了finally(和catch)的范围

您担心的是声明可能会引发运行时错误

基于注释OP不知道初始化可以与声明分开

    List<string>  testLString;        
    try
    {
        testLString = new List<string>();
    }
    catch (Exception ex)
    {
    }
    finally
    {
        testLString = null;
    }
List testLString;
尝试
{
testLString=新列表();
}
捕获(例外情况除外)
{
}
最后
{
testLString=null;
}
我不同意您对声明可能引发运行时错误的担忧。

它只做声明。

您可以根据需要嵌套任意多个
try…catch
结构。这是让代码负责自己清理的好方法

对于总是需要清理的代码,无论其是否正常,也可以考虑使用一个结构,该结构只有
try
finally

try {

  // do something here

  // declare some variable
  try {
    // allocate space for variable
    // do something with that variable
  } fincally {
    // deallocate space for variable
  }

  // do something more here

} catch(Exception ex) {
  // handle the exception here
}
您应该尝试使用尽可能具体的异常类,并且可以在同一结构中使用不同的类型来捕获不同的异常:

try {
  // do some i/o
} catch (IOException ex) {
  // here you know that it was actually the i/o that failed
} catch (Exception ex) {
  // here is for catching anything else that might have failed
}

我建议您创建一个单独的类型,它包装与非托管API的所有通信,管理内存等。它实现了
IDisposable
接口,该接口的实现负责清理所有非托管资源。如果您在Windows上,最干净的方法是在C++/CLI中实现此包装器

我想这对我不起作用。我希望在最外层的try catch中有一些示例:“NativeOverlapped HidOverlapped=new NativeOverlapped();”IntPtr eventObject=CreateEvent(IntPtr.Zero,false,false,“”;“”)IntPtr nonManagedOverlapped=Marshal.AllocHGlobal(Marshal.SizeOf(HidOverlapped));“”Marshal.StructureToPtr(HidOverlapped、nonManagedOverlapped、false);'我还在初始化数组的一个元素。为了安全起见,我还必须假设在初始化时可能出现错误(例如IndexOutOfBounds异常)。有什么想法吗?使用一个单独的函数来完成工作(读写文件)怎么样?这样,这个新函数将有自己的try-and-catch块。但是,如果被调用函数中的catch块抛出并处理异常,程序是否会返回调用方函数?1您可以在块中添加try-catch,方法是在非ManagedOverlapped中使用2 set using block,这是值得注意的-using语句是try finally的语法糖,因此,如果您想捕获using语句中发生的异常,则需要用它自己的try catch进行封装。@Jamie:我刚刚读了一些关于using语句的内容,得出了与您相同的结论。在编译时,using语句将被展开以最终重试。所以在try-catch中使用using实际上是嵌套try-catch块。我说的对吗?这正是我关心的问题。由于我也在初始化变量(不仅仅是声明变量),我担心会出现错误。简单地说,我想将函数“拆分”为两部分:1)准备工作所需的一切(声明和初始化变量、结构等等;准备内存非托管部分中的一切,…)2)做实际工作我想“涵盖”这两部分对于异常。您知道可以分别初始化和声明吗?
try {
  // do some i/o
} catch (IOException ex) {
  // here you know that it was actually the i/o that failed
} catch (Exception ex) {
  // here is for catching anything else that might have failed
}