Ignoring exceptions - c#

I have some code which ignores a specific exception.
try
{
foreach (FileInfo fi in di.GetFiles())
{
collection.Add(fi.Name);
}
foreach (DirectoryInfo d in di.GetDirectories())
{
populateItems(collection, d);
}
}
catch (UnauthorizedAccessException ex)
{
//ignore and move onto next directory
}
of course this results in a compile time warning as ex is unused. Is there some standard accept noop which should be used to remove this warning?

Just rewrite it as
catch (UnauthorizedAccessException) {}

As Dave M. and tvanfosson said, you want to rewrite it as
catch (UnauthorizedAccessException) {}
The bigger question that should be asked, however, is why you are catching an exception on ignoring it (commonly called swallowing the exception)? This is generally a bad idea as it can (and usually does) hide problems in the application at runtime that can lead to very strange results and a difficult time debugging them.

I usually do
Debug.WriteLine(ex.message)
(that way I can just set a breakpoint in the exception, if needed, too)

Assuming the comment in your original code is an accurate description of what you're trying to do, I think you want to write it like this:
foreach (FileInfo fi in di.GetFiles())
{
//TODO: what exceptions should be handled here?
collection.Add(fi.Name);
}
// populate collection for each directory we have authorized access to
foreach (DirectoryInfo d in di.GetDirectories())
{
try
{
populateItems(collection, d);
}
catch (UnauthorizedAccessException)
{
//ignore and move onto next directory
}
}
And then you need to work on that TODO item.

I agree with the people who say it's probably a bad idea to simply ignore the exception. If you're not going to re-throw it then at the very least log it somewhere. I've written small tools that process a list of files where I didn't want errors on individual files to crash the whole program, and in such cases I would print a warning message so I could see which files were skipped.
The only time I personally ever catch an exception without naming it, as in catch(xxxException), is if I'm going to react to it in some way and then re-throw it so that I can catch it in some outer routine. E.g.:
try
{
// do something
// ...
}
catch(UnauthorizedAccessException)
{
// react to this exception in some way
// ...
// let _someone_ know the exception happened
throw;
}

Even though I'm a Java developer (not C#), #Scott Dorman is absolutely right. Why are you "swallowing the exception"? Better yet, what could throw the UnauthorizedAccessException? Here are common-sense possibilities:
The file doesn't exist
The directory doesn't exist
The current thread of control does not have the correct security privileges. In the *nix world, the current thread may be in the wrong group or the wrong user.
The disk crashed
The file's ACL is set to write only but not read. Likewise, for the directory.
The above of course is an incomplete list.

Related

Ignore Exception at a certain Location while debugging?

Our Application is moving some files it requires to run during startup.
The application takes care (on shutdown) to properly stop every process using this files.
However, if the application crashes / or you just hit "stop" in VS on Debugging - some executables might still be running.
So, if you quickly restart the application, it might happen, that the copy-attempt is failing, due to the file is still in use.
For such a case, we just ignore the failed copy attempt - or more exactly: the failed deletion attempt which should make sure, that the latest version is available:
foreach(String entry in contents)
{
if (System.IO.File.Exists(entry))
{
try
{
System.IO.File.Delete(entry);
}catch (Exception e)
{
//ignore during this startup.
}
}
}
Now, this works perfectly fine, as there is a version of the file available for usage and the production version just ignores the exception.
The annoying Problem is, that the Debugger "breaks" everytime, this error happens.
We don't want to generally "ignore" any System.IO.IOException thrown while debugging.
We tried to annotate the method in Question with [System.Diagnostics.DebuggerStepThrough()] which works, but causes the exception to be catched at the callers position.
So, is there a way to ignore "some" exceptions raised at a certain line of code, even if general "breaking" for that kind is enabled?
Some #if (DEBUG)-Directives which will avoid the exception to be catched at this particular line of code?
Something like:
foreach(String entry in contents)
{
if (System.IO.File.Exists(entry))
{
try
{
#if (DEBUG:NoThrow)
System.IO.File.Delete(entry);
#endif
}catch (Exception e)
{
//ignore during this startup.
}
}
}
I'm still interested in an answer, cause it has "many" usecases.
For the time beeing, we used the following "workaround": Check, if the file has been accessed withing 3 minutes - then don't attempt to delete it.
(For DEBUG-Mode!)
Remember, the actual issue is only about the "debugger", not production, where Exceptions can be caught (and ignored) easily for a certain line of code.
We just want to avoid "Debugger-Breaks" kicking in if the exception can savely be ignored AT THIS line of code.
foreach (String entry in contents)
{
if (System.IO.File.Exists(entry))
{
try {
#if (DEBUG)
FileInfo fi = new FileInfo(entry);
if (fi.LastAccessTime < DateTime.Now.AddMinutes(-3))
{
#endif
System.IO.File.Delete(entry);
#if (DEBUG)
}
#endif
}
catch (Exception e)
{
//ignore
}
}
}
This is NOT a solution, it's a workaround, reducing the Debugger-Breaks at this line of code by about 99%, in case you just "Stop" Debuggin within Visual Studio!

What is a better way to handle exceptions than the following?

At first, I was going to do something like the following:
public void WriteToFile(string filePath, string contents)
{
try
{
File.WriteAllText(filePath, contents)
}
catch(Exception ex)
{
//Log error
}
}
But then I decided to catch all the specific exceptions for the method WriteAllText, like the following:
public void WriteToFile(string filePath, string contents)
{
try
{
File.WriteAllText(filePath, contents);
}
catch (IOException ex)
{
//An I/O error occured when opening the file
}
catch (ArgumentException ex)
{
//The exception that is thrown when one of the arguments provided to a method
that is not valid.
}
catch (UnauthorizedAccessException ex)
{
//Unauthorized access
}
catch (SecurityException ex)
{
//Security exception
}
catch (NotSupportedException ex)
{
//Invoked method not supported
}
}
The above is very verbose and with other methods, it could be more. Is there a better way to do this so I don't have to write so many catch statements. Also, if an exception is caught, is it best to return from it, log it. I always get confused on how to handle it.
I have noticed some confusion. I am going to handle the exceptions, I left out handling the exception to keep this short. I am going to make use of the ex variable. The question is more about doing just catch(Exception ex) or multiple catch statements.
I also bring this up because I always here that it is better to handle specific exceptions rather than a catch-all. If I have misunderstood this, please clarify on what it means.
It depends on how you are handling the exception. For example, if a SecurityException will cause you to present a dialog to the user to provide their credentials, then you should have a separate catch clause. If not, there is no need to explicitly call them all out.
E.g.
try
{
File.WriteAllText(filePath, contents);
}
catch (SecurityException ex)
{
//present dialog
}
catch (Exception ex)
{
//All other exceptions handled the same
}
Typicaly, your try/catch statements will be much further up the call stack from what you are showing in the question. There are two major reasons for this. First is that a low-level method will not know how to deal with an exception that happens within it, because it does not have enough context. If a low-level method (such as one that saves a document) does know enough about its circumstances to handle the exceptions, then that is a sign of a leaky abstraction. Second is that the program flow at higher levels will depend on whether the save operation succeeded or not. For these reasons, all of these types of exceptions are best delt with at the highest levels, such as in the UI layer.
That said, sometimes a long list of exceptions—as you have it—is exactly the way to go. If you need to handle a bunch of different circumstances, then it calls for a bunch of different catch statements, and that's just the way it goes.
Some of those exceptions, however, do not need to be caught. For example, an ArgumentException never needs to be caught. Instead, it is best just to pass the correct arguments every time. The only time an ArgumentException will ever need to be caught is if you are calling into a poory designed library in which you cannot know beforehand whether an argument is good or not. A well-designed library will provide alternatives to this.
So the list of catch statements could be made shorter, just by judiciously examining the circumstances of each type of exception and determining which ones are actually expected to happen.
I agree with SLaks above. If you don't handle it there is no reason in catching specific exceptions. If you can handle certain exceptions but not others you should have a catch all that at least logs vital information about the exception.
The best method very much depends on the nature of your application and the expectations of the user. If you are creating a Word processing application and your operation above was to save the user's document, swallowing the exception and logging without notifying the user would be very bad! In this context, I would catch the specific exceptions so that I could better report to the user what the problem is.
If instead the file you are saving is non-critical, e.g. a period caching of some data that is retained in memory, you might want to simply log and not notify the user. In this context, I would go for a generic catch-all and just log the exception details.

Common programming mistakes in .Net when handling exceptions? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
What are some of the most common mistakes you've seen made when handling exceptions?
It seems like exception handling can be one of the hardest things to learn how to do "right" in .Net. Especially considering the currently #1 ranked answer to Common programming mistakes for .NET developers to avoid? is related to exception handling.
Hopefully by listing some of the most common mistakes we can all learn to handle exceptions better.
What are some of the most common mistakes you've seen made when handling exceptions?
I can think of lots.
First read my article on categorization of exceptions into vexing, boneheaded, fatal and exogenous:
http://ericlippert.com/2008/09/10/vexing-exceptions/
Some common errors:
Failure to handle exogenous exceptions.
Failure to handle vexing exceptions.
Construction of methods that throw vexing exceptions.
Handling exceptions that you actually cannot handle, like fatal exceptions.
Handling exceptions that hide bugs in your code; don't handle a boneheaded exception, fix the bug so that it isn't thrown in the first place
Security error: failure to the unsafe mode
try
{
result = CheckPassword();
if (result == BadPassword) throw BadPasswordException();
}
catch(BadPasswordException ex) { ReportError(ex); return; }
catch(Exception ex) { LogException(ex); }
AccessUserData();
See what happened? We failed to the unsafe mode. If CheckPassword threw NetworkDriverIsAllMessedUpException then we caught it, logged it, and accessed the user's data regardless of whether the password was correct. Fail to the safe mode; when you get any exception, assume the worst.
Security error: production of exceptions which leak sensitive information, directly or indirectly.
This isn't exactly about handling exceptions in your code, it's about producing exceptions which are handled by hostile code.
Funny story. Before .NET 1.0 shipped to customers we found a bug where it was possible to call a method that threw the exception "the assembly which called this method does not have permission to determine the name of file C:\foo.txt". Great. Thanks for letting me know. What is stopping said assembly from catching the exception and interrogating its message to get the file name? Nothing. We fixed that before we shipped.
That's a direct problem. An indirect problem would be a problem I implemented in LoadPicture, in VBScript. It gave a different error message depending upon whether the incorrect argument is a directory, a file that isn't a picture, or a file that doesn't exist. Which means you could use it as a very slow disk browser! By trying a whole bunch of different things you could gradually build up a picture of what files and directories were on someone's hard disk. Exceptions should be designed so that if they are handled by untrustworthy code, that code learns none of the user's private information from whatever they did to cause the exception. (LoadPicture now gives much less helpful error messages.)
Security and resource management error: Handlers which do not clean up resources are resource leaks waiting to happen. Resource leaks can be used as denial-of-service attacks by hostile partial trust code which deliberately creates exceptions-producing situations.
Robustness error: Handlers must assume that program state is messed up unless handling a specific exogenous exception. This is particularly true of finally blocks. When you're handling an unexpected exception, it is entirely possible and even likely that something is deeply messed up in your program. You have no idea if any of your subsystems are working, and if they are, whether calling them will make the situation better or worse. Concentrate on logging the error and saving user data if possible and shut down as cleanly as you can. Assume that nothing works right.
Security error: temporary global state mutations that have security impacts need to be undone before any code that might be hostile can run. Hostile code can run before finally blocks run! See my article on this for details:
http://blogs.msdn.com/ericlippert/archive/2004/09/01/224064.aspx
Re-throwing exceptions like this:
try
{
// some code here
}
catch(Exception ex)
{
// logging, etc
throw ex;
}
This kills the stack trace, making is far less usable. The correct way to rethrow would be like this:
try
{
// some code here
}
catch(Exception ex)
{
// logging, etc
throw;
}
Catching all exceptions when in many cases you should attempt to catch specific exceptions:
try {
// Do something.
} catch (Exception exc) {
// Do something.
}
Rather than:
try {
// Do something.
} catch (IOException exc) {
// Do something.
}
Exceptions should be ordered from most specific to least.
Rethrowing an exception with a meaningless message.
try
{
...
}
catch (Exception ex)
{
throw new Exception("An error ocurred when saving database changes").
}
You won't believe how often I see code like this running in production.
Nobody is talking about seeing empty catch blocks like these....
try{
//do something
}
catch(SQLException sqex){
// do nothing
}
Also never use Exception handling for creating alternate method flows...
try{
//do something
}catch(SQLException sqex){
//do something else
}
Not using using on IDisposable objects:
File myFile = File.Open("some file");
callSomeMethodWhichThrowsException(myFile);
myFile.Close();
myFile does not get closed until myFile's finalizer is called (which may be never) because an exception was thrown before myFile.Close() was called.
The proper way to do this is
using(File myFile = File.Open("some file"))
{
callSomeMethodWhichThrowsException(myFile);
}
This gets translated by the compiler into something like:
File myFile = File.Open("some file");
try
{
callSomeMethodWhichThrowsException(myFile);
}
finally
{
if(myFile != null)
myFile.Dispose(); //Dispose() calls Close()
}
So the file gets closed even in the face of exceptions.
Forget to set the inner exception when rethrowing a catched exception
try
{
...
}
catch (IOException ioException)
{
throw new AppSpecificException("It was not possible to save exportation file.")
// instead of
throw new AppSpecificException("It was not possible to save exportation file.", ioException);
}
When I posted this answer, I forget to mention that we should always consider when to include inner exception or not due to security reasons. As Eric Lippert pointed out on another answer for this topic, some exceptions can provide sensitive information about the implementation details of the server. Thus, if the caller who will be handling the exception is not trusted, it is not a good idea to include the inner exception information.
Empty catch:
//What's the point?
catch()
{}
Rethrowing:
//Exceptions are for *adding* detail up the stack
catch (Exception ex)
{throw ex;}
Assuming an exception that covers many scenarios was something specific. A real life scenario was a web app where the exception handling always assumed all errors were session time outs and logged and reported all errors as session time outs.
Another example:
try
{
Insert(data);
}
catch (SqlException e)
{
//oh this is a duplicate row, lets change to update
Update(data);
}
To log Exception.Message instead of Exception.ToString()
Many times, I see code logging only the exception message while it should log the return of ToString method. ToString provides much more information about the exception than the Message. It includes information like inner exception and stack trace besides the message.
Trying to catch OutOfMemoryException or StackOverflowException - those lead to a shutdown of the runtime, hence to way to catch them from within the same Process (or even from the CLR as a whole?)
OutOfMemoryException: The exception that is thrown when there is not enough memory to continue the execution of a program.
"Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow."
Failing to catch possible exceptions inside a catch handler. This can cause the wrong exception to be propagated upwards.
For example:
try
{
DoImportantWork();
}
catch
{
Cleanup();
throw;
}
What happens if Cleanup() throws an exception? You don't want to see an Exception pointing to the Cleanup() method in this catch handler. You want the original error. You could try to log the cleanup error, but even your logging code needs exception handling to avoid throwing exceptions from it.
try
{
DoImportantWork();
}
catch
{
try
{
Cleanup();
}
catch
{
// We did our best to clean up, and even that failed.
// If you try to log this error, the logging may throw yet another Exception.
}
throw;
}
Wrong
try
{
// Do something stupid
}
catch
{
// ignore the resulting error because I'm lazy, and later spend
// a week trying to figure out why my app is crashing all over
// the place.
}
Better
try
{
/// do something silly.
}
catch (InvalidOperationException ex)
{
/// respond, or log it.
}
catch (Exception e)
{
/// log it.
}
Using exceptions for normal flow control. Exceptions should exceptional. If it's a good / expected operation, use return values, etc.

Can't declare unused exception variable when using catch-all pattern

what is a best practice in cases such as this one:
try
{
// do something
}
catch (SpecificException ex)
{
Response.Redirect("~/InformUserAboutAn/InternalException/");
}
the warning i get is that ex is never used.
however all i need here is to inform the user, so i don't have a need for it.
do i just do:
try
{
// do something
}
catch
{
Response.Redirect("~/InformUserAboutAn/InternalException/");
}
somehow i don't like that, seems strange!!? any tips? best practices?
what would be the way to handle this.
thnx
You just don't declare the variable:
try
{
// do something
}
catch (SpecificException)
{
Response.Redirect("~/InformUserAboutAn/InternalException/");
}
This is a moot point when catching System.Exception (in your original example, which is not exactly the same as an empty catch -- an empty catch will also catch COM exceptions, for instance), but this is the correct construct to use.
If you run your code through other analysis engines (Gendarme, for instance), you will also be warned that catching a plain Exception is poor practice because it can mask other exceptions besides what you really wanted to catch. That's bitten me a few times while maintaining legacy code -- we were catching and ignoring an Exception on a file delete (or something like that), but the main logic wasn't working correctly. We should have been only catching an IOException, but we were catching and discarding the NullReferenceException that was causing the failure.
That's not to say you never should catch Exception; just rarely.
If you don't need Exception's variable to get some information from it, don't declare it
try { }
catch ( )
is equal to
try { }
catch (Exception) { }
Use this
try { }
catch (Exception ex) { var m = ex.Message; }
if you need some information to gather.
Use this
try { }
catch (FooException) { }
catch (BarException) { }
if you need to catch only specific types of exceptions, i.e. SomeAnotherException will not be caught.
It would be better if you just let the exception bubble all the way up and use an application wide exception handler or something like ELMAH. Usually you'll want to log the exception or something so there's a record of stuff failing.
Any reason why you wouldn't let unhandled exceptions simply throw and use the Application Level error handling built into ASP.NET? See How to: Handle Application-Level Errors for more details.
I usually declare it and suffer with the warning since it can be very useful to be able to look at the exception details while debugging.
There are two reasons to declare an exception variable in a catch block. To catch only specific exception types or to do something with the exception info. In your case you are doing neither so t serves no purpose.

Use case for try-catch-finally with both catch and finally

I understand how try-catch works and how try-finally works, but I find myself using those (usually) in two completely different scenarios:
try-finally (or using in C# and VB) is mostly used around some medium-sized code block that uses some resource that needs to be disposed properly.
try-catch is mostly used either
around a single statement that can fail in a very specific way or
(as a catch-all) at a very high level of the application, usually directly below some user interface action.
In my experience, cases where a try-catch-finally would be appropriate, i.e., where the block in which I want to catch some particular exception is exactly the same block in which I use some disposable resource, are extremely rare. Yet, the language designers of C#, VB and Java seem to consider this to be a highly common scenario; the VB designers even think about adding catch to using.
Am I missing something? Or am I just overly pedantic with my restrictive use of try-catch?
EDIT: To clarify: My code usually looks like this (functions unrolled for clarity):
Try
do something
Aquire Resource (e.g. get DB connection)
Try
do something
Try
do something that can fail
Catch SomeException
handle expected error
do something else...
Finally
Close Resource (e.g. close DB connection)
do something
Catch all
handle unexpected errors
which just seems to make much more sense than putting any of the two catches on the same level as finally just to avoid indentation.
A quote from MSDN
A common usage of catch and finally
together is to obtain and use
resources in a try block, deal with
exceptional circumstances in a catch
block, and release the resources in
the finally block.
So to make it even more clear, think of the code that you want to run, in 99% of the cases it runs perfectly well but somewhere in the chunk there might occure an error, you don't know where and the resources created are expensive.
In order to be 100% sure that the resources are disposed of, you use the finally block, however, you want to pin-point that 1% of cases where the error occures, therefore you might want to set up logging in the catch-ing-section.
That's a very common scenario.
Edit - A Practical Example
There is some good examples here: SQL Transactions with SqlTransaction Class. This is just one of the many ways to use Try, Catch & Finally and it demonstrates it very well, even though a using(var x = new SqlTranscation) might be efficient some times.
So here goes.
var connection = new SqlConnection();
var command = new SqlCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
Here comes the more interesting parts
///
/// Try to drop a database
///
try
{
connection.Open();
command.CommandText = "drop database Nothwind";
command.ExecuteNonQuery();
}
So let's imagine that the above fails for some reason and an exception is thrown
///
/// Due to insufficient priviligies we couldn't do it, an exception was thrown
///
catch(Exception ex)
{
transaction.Rollback();
}
The transaction will be rolled back! Remember, changes you made to objects inside the try/catch will not be rolled back, not even if you nest it inside a using!
///
/// Clean up the resources
///
finally
{
connection.Close();
transaction = null;
command = null;
connection = null;
}
Now the resources are cleaned up!
Not an answer to your question, but a fun fact.
The Microsoft implementation of the C# compiler actually cannot handle try-catch-finally. When we parse the code
try { Foo() }
catch(Exception e) { Bar(e); }
finally { Blah(); }
we actually pretend that the code was written
try
{
try { Foo(); }
catch(Exception e) { Bar(e); }
}
finally { Blah(); }
That way the rest of the compiler -- the semantic analyzer, the reachability checker, the code generator, and so on -- only ever has to deal with try-catch and try-finally, never try-catch-finally. A bit of a silly early transformation in my opinion, but it works.
Example:
Try
Get DB connection from pool
Insert value in table
do something else...
Catch
I have an error... e.g.: table already contained the row I was adding
or maybe I couldn't get the Connection at all???
Finally
if DB connection is not null, close it.
You can't really get a more "common" example. Pity that some people still forget to put the close connection in the Finally, where it belongs, instead of in the Try block... :(
I often write code that looks like this:
Handle h = ...
try {
// lots of statements that use handle
} catch (SomeException ex) {
// report exception, wrap it in another one, etc
} catch (SomeOtherException ex) {
// ...
} finally {
h.close();
}
So maybe you are just being overly pedantic ... e.g. by putting a try / catch around individual statements. (Sometimes it is necessary, but in my experience you don't usually need to be so fine-grained.)
There is nothing wrong with nesting try/catch/finally blocks. I actually use this quite often. I.e. when I use some resource that needs to be disposed or closed but I want only a single catch block around a larger code unit that needs to be aborted if some error occurs inside it.
try {
// some code
SomeResource res = new SomeResource();
try {
res.use();
} finally {
res.close();
}
// some more code
} catch( Exception ex ) {
handleError( ex );
}
This closes the resource as early as possible in either case (error or not) but still handles all possible errors from creating or using the resource in a single catch block.
I think you are quite right. From the .Net Framework Design Guidelines, written by some of the top architects at Microsoft:
DO NOT overcatch. Exceptions should
often be allowed to propagate up the
call stack.
In well-written code, try-finally [or
using] is far more common than
try-catch. It might seem
counterintuitive at first, but catch
blocks are not needed in a surprising
number of cases. On the other hand,
you should always consider whether
try-finally [or using] could be of use
for cleanup.
page 230 section 7.2
I would nearly always use try-catch-finaly in cases where you need to dispose something in all cases and you use the case to log the error and/or inform the user.
How about something like:
Dim mainException as Exception = Nothing
Try
... Start a transaction
... confirm the transaction
Catch Ex as Exception
mainException = Ex
Throw
Finally
Try
... Cleanup, rolling back the transaction if not confirmed
Catch Ex as Exception
Throw New RollbackFailureException(mainException, Ex)
End Try
End Try
Assuming here that the RollbackFailureException includes an "OriginalException" field as well as "InnerException", and accepts parameters for both. One doesn't want to hide the fact that an exception occurred during the rollback, but nor does one want to lose the original exception which caused the rollback (and might give some clue as to why the rollback happened).
Another use would be to dispose a file handle to an e-mail attachment when using the System.Web.Mail mail objects to send e-mail. I found this out when I had to programatically open a Crystal Report, save it to disk, attach it to an e-mail, and then delete it from disk. An explicit .Dispose() was required in the Finally to make sure I could delete it, especially in the event of a thrown exception.
In my experience, cases where a try-catch-finally would be appropriate, i.e., where the block in which I want to catch some particular exception is exactly the same block in which I use some disposable resource, are extremely rare. Yet, the language designers of C#, VB and Java seem to consider this to be a highly common scenario; the VB designers even think about adding catch to using.
you:
try {
//use resource
} catch (FirstException e) {
// dispose resource
// log first exception
} catch (SecondException e) {
// dispose resource
// log first exception
} catch (ThirdException e) {
// dispose resource
// log first exception
}
me:
try {
//use resource
} catch (FirstException e) {
// log first exception
} catch (SecondException e) {
// log first exception
} catch (ThirdException e) {
// log first exception
} finally {
// dispose resource
}
feel defference?)

Categories

Resources