简体   繁体   中英

Cleaning up after variable declaration, initialization and unamanaged memory allocation

I would like to kindly ask for your advice on a good programming practice in c# when it comes to defining variables, allocating space for them, initializing them and then properly cleaning up everything.

The problem I am facing at the moment is, that I have a function which uses unmanaged API functions and as a result also accesses unmanaged memory (Marshaling is used). I would like to make the function clean and properly dispose of everything before exiting. The thing is though, that all actual work is done inside a try-catch block. Which means that I can not clean everything in a catch or finally block.

What I've done is declare all variables, reserve memory for them and initialized them right after entering the function and then clean everything up (close handles, release memory,...) in finally block.

All good but I would also like to have variable declaration, initialization and memory allocation done in a try block (something can also go wrong when initializing an array for example or allocating space in memory or God knows where). The only thing which comes to mind is nesting two try-catch blocks. Is this OK or would you propose something else?

Here is what I have so far:

//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,...)
}

And here is what I have in mind:

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,...)
}

Thanks in advance for all your help!

Cheers!

You can implement IDisposable interface in order to call Dispose method.

Or as best practise use block using

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

 ...

}

The particularity of using block is that call Dispose Method in the end of treatment.

For example if you use SqlConnection

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

}

Just this code is sufficient

Link : http://msdn.microsoft.com/fr-fr/library/vstudio/system.idisposable.aspx

Link : http://msdn.microsoft.com/fr-fr/library/yh598w02%28v=vs.80%29.aspx

Problem with that approach is variable is out of scope in the finally (and catch)

    try
    {
        string testString;
    }
    catch (Exception ex)
    {
    }
    finally
    {
        // testString is not in scope
    }

Your concern is that the declaration may throw a run time error?

Based on comment OP is not aware initialization can be separate from declaration.

    List<string>  testLString;        
    try
    {
        testLString = new List<string>();
    }
    catch (Exception ex)
    {
    }
    finally
    {
        testLString = null;
    }

I don't agree with your concern that a declaration might throw a run time error.
It does nothing but declare.

You can nest as many try...catch structures as you want or need. It's a good way to make the code take responsibility for its own cleanup.

Consider also using a structure with just try and finally for code that always needs cleanup, regardless of whether it went ok or not:

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
}

You should try to use an exception class that is as specific as possible, and you can use different types in the same structure to catch different exceptions:

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
}

I'd advise you to create a separate type which wraps all the communication with the unmanaged APIs, manages memory etc. It implements the IDisposable interface the implementation of which takes care of cleaning up all unmanaged resources. If you are on Windows, the cleanest way to accomplish this is to implement this wrapper in C++/CLI.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM