In our codebase, we have a battery of custom error checking functions (like those listed here) to check arguments less verbosely. For example, to check an argument for null I use:
Throw.IfNull(theArgument, "theArgument");
The one disadvantage of this approach is that R# gives the warning "possible NullReferenceException" on future uses of the value because it's not smart enough to detect this as a null check (or at least something that would fail if theArgument were null). Is there any way to indicate that this method checks against the argument being null? For example, when I try to run a static extension like Select() on such a value, R# warns me of 'possible null assignment to entity marked with NotNull attribute', but I can't find any documentation of such an attribute nor do I see it in the reference source for Enumerable.Select().
What you're asking can definitely be solved by applying ReSharper Annotations! Those are attributes that provide additional hints for ReSharper's analysis, allowing you to add ReSharper "goodness" onto your own methods and classes. I have recently recorded a webinar with JetBrains called ReSharper Secrets where I talk about and demonstrate annotations, you're welcome to watch it!
As to your question, there are 3 annotation attributes you can apply to solve your issues (and add more cool features).
Supposing the definition for IfNull
is something like:
public static class Throw
{
public static void IfNull<T>(T parameter, string parameterName) where T : class
{
if (parameter == null)
throw ArgumentNullException(string.Format("Parameter {0} is null", parameterName));
}
}
You can decorate it with 3 ReSharper attributes, ContractAnnotation
, NotNull
and InvokerParameterName
like this:
[ContractAnnotation("parameter: null => halt")]
public static void IfNull<T>([NotNull] T parameter,
[InvokerParameterName] string parameterName)
where T : class
{
...
}
Here is what those attributes do:
The first, [ContractAnnotation]
, tells ReSharper that if parameter
is heuristically null, then this method halts the program execution, i.e. throws exception (at runtime). This is what prevents the "possible NullReferenceException" warning. The language used for defining Contract annotations is explained here.
The second is [NotNull]
, tells ReSharper that parameter
must not be heuristically null. This gives the "Possible null assignment to entity marked with [NotNull] attribute" warning.
The third, [InvokerParameterName]
is telling ReSharper that the parameterName
argument is the name of one of the parameters from the calling (invoking) method, so it will provide code completion that lists all the calling method parameters. This will give a warning in ReSharper if the name is not a parameter, for example, a local variable name.
Here's a short video of these attributes in action (applied to another set of APIs, but the idea is exactly the same): http://screencast.com/t/NhGVaUr7GO3b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With