I am currently writing a small framework that will be used internally by other developers within the company.
I want to provide good Intellisense information, but I am not sure how to document thrown exceptions.
In the following example:
public void MyMethod1()
{
MyMethod2();
// also may throw InvalidOperationException
}
public void MyMethod2()
{
System.IO.File.Open(somepath...); // this may throw FileNotFoundException
// also may throw DivideByZeroException
}
I know the markup for documenting exceptions is:
/// <exception cref='SomeException'>when things go wrong.</exception>
What I don't understand is how to document exceptions thrown by code called by MyMethod1()
?
- Should I document exceptions thrown by
MyMethod2()
- Should I document exceptions thrown by
File.Open()
?
What would be the best way to document possible exceptions?
Answers:
You should document all exceptions that could possibly be thrown by your method.
To hide the implementation details, I would try to handle some exceptions from MyMethod2 myself.
You could consider retrowing them, if you cannot handle or solve the exception. Mostly packaged/wrapped in a more meaningfull exception for the caller.
Answers:
Document expected exceptions in your method, in your example I would let the user know that that method can throw a file not found exception.
Remember that it is to inform the caller of what to expect so they can choose how to deal with it.
Answers:
From what I understand, the intention of using the <exception> element is to use it when decorating methods, not exceptions:
/// <summary>Does something!</summary>
/// <exception cref='DidNothingException'>Thrown if nothing is actually done.</exception>
public void DoSomething()
{
// There be logic here
}
Exceptions that can be thrown by other methods that are called should be caught, handled and documented in those methods. Exceptions that could possibly thrown by .NET, or exceptions that are explicitly thrown by your own code should be documented.
As far as getting any more specific than that, perhaps you can catch and throw your own customized exceptions?
Answers:
You should use the standard xml documentation.
/// <exception cref='InvalidOperationException'>Why it's thrown.</exception>
/// <exception cref='FileNotFoundException'>Why it's thrown.</exception>
/// <exception cref='DivideByZeroException'>Why it's thrown.</exception>
public void MyMethod1()
{
MyMethod2();
// ... other stuff here
}
/// <exception cref='FileNotFoundException'>Why it's thrown.</exception>
/// <exception cref='DivideByZeroException'>Why it's thrown.</exception>
public void MyMethod2()
{
System.IO.File.Open(somepath...);
}
/// <exception cref='FileNotFoundException'>Why it's thrown.</exception>
public void MyMethod3()
{
try
{
MyMethod2();
}
catch (DivideByZeroException ex)
{
Trace.Warning('We tried to divide by zero, but we can continue.');
}
}
The value in doing it this way is that you are providing documentation of the known exceptions that can occur. This documentation is available in the intellisense if you are using visual studio and can remind you (or others) later of the exceptions that you can expect.
You want to specify the specific exception types, because you may be able to handle one type of exception, while other types are the result of a serious issue and can not be corrected.
Answers:
You should document every exception that might be thrown by your code, including those in any methods that you might call.
If the list gets a bit big, you might want to create your own exception type. Catch all the ones you might encounter within your method, wrap them in your exception, and throw that.
Another place you might want to do it this way is if your method is on the face of your API. Just like a facade simplifies multiple interfaces into a single interface, your API should simplify multiple exceptions into a single exception. Makes using your code easier for callers.
To answer some of Andrew's concerns (from the comments), there are three types of exceptions: Ones you don't know about, ones you know about and can't do anything about, and ones you know about and can do something about.
The ones you don't know about you want to let go. Its the principal of failing fast--better your app to crash than enter a state where you might end up corrupting your data. The crash will tell you about what happened and why, which may help move that exception out of the 'ones you don't know about' list.
The ones you know about and can't do anything about are exceptions like OutOfMemoryExceptions. In extreme cases you might want to handle exceptions like this, but unless you have some pretty remarkable requirements you treat them like the first category--let 'em go. Do you have to document these exceptions? You'd look pretty foolish documenting OOMs on every single method that new-s up an object.
The ones you know about and can do something about are the ones you should be documenting and wrapping.
You can find some more guidelines on exception handling here.
Answers:
Part of the contract for your method should be to check that the pre-conditions are valid, so:
public void MyMethod2()
{
System.IO.File.Open(somepath...); // this may throw FileNotFoundException
}
becomes
/// <exception cref='FileNotFoundException'>Thrown when somepath isn't a real file.</exception>
public void MyMethod2()
{
FileInfo fi = new FileInfo( somepath );
if( !fi.Exists )
{
throw new FileNotFoundException('somepath doesn't exists')
}
// Maybe go on to check you have permissions to read from it.
System.IO.File.Open(somepath...); // this may still throw FileNotFoundException though
}
With this approach, it's easier to document all the exceptions you explicitly throw without having to also document that a OutOfMemoryException
might be thrown, etc.
Answers:
You can make your documentation process easier by using several great add-ins. One of them is GhostDoc, a free add-in for Visual Studio which generates XML-doc comments. Also, if you use ReSharper, have a look at the excellent Agent Johnson Plugin for ReSharper, which adds an option to generate XML comments for thrown exceptions.
Update: It seems that Agen Johnson is not available for R# 8, checkout Exceptional for ReSharper as an alternative...
Step 1: GhostDoc generates the XML comment (Ctrl-Shift-D), while Agent Johnson plugin for ReSharper suggests documenting the exception as well:
Step 2: Use ReSharper's shortcut key (Alt-Enter) to add the exception documentation as well:
step 2 http://i41.tinypic.com/osdhm
Hope that helps :)
Answers:
Indeed, as it has been already answered, the way to document the exceptions is using XML Comments.
In addition to the plugins, you can also use static analysis tools that can be integrated with TFS to be sure you have the exceptions documented.
In the links below you can see how to build a custom rule for StyleCop to validate the exceptions thrown by your methods are being documented.
http://www.josefcobonnin.com/post/2009/01/11/Xml-Documentation-Comments-Exceptions-I.aspx http://www.josefcobonnin.com/post/2009/01/15/Xml-Documentation-Comments-Exceptions-II.aspx
Regards.
No comments:
Post a Comment