Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I tag a C# function as "this function does not enumerate the IEnumerable parameter"?

Multiple enumeration of the same enumerable is something that has been a performance problem for us, so we try to stomp those warnings in the code. But there is a generic extension function that we have for throwing null parameter exceptions that generates a lot of these warnings. Its signature looks like this:

public static void VerifyArgumentIsNotNull<T>(this T value, string valueName) where T : class

All it does is check for null and throw a nicely formatted and localized (for whichever human language is in play at the time) exception.

When this function is used on an IEnumerable parameter, it makes the code analysis warn about a possible multiple iteration of the IEnumerable because the analyzer has no idea what that function does.

I would like to put some tag on this function that says, "Yes, this takes the enumerable as an input, but it does not iterate it and therefore should not be counted as a possible iteration by callers." Is there any such tag? I've searched the Internet to no avail.

like image 469
srm Avatar asked May 08 '14 15:05

srm


1 Answers

Yes, what you're asking is very much possible, but requires a little work. ReSharper uses Code Annotations to add hints to its analysis engine and make more sense of the code it has to work with. I recently recorded a webinar with JetBrains called ReSharper Secrets, where I go into much greater detail about what Annotations are and how to use them. You should watch it!

There's an annotation attribute, [NoEnumeration] that does exactly what you ask - specifies that the given IEnumerable argument is not enumerated, however it's not included in the default Code Annotation Attributes, however it is defined in the JetBrains.Annotations.dll assembly.

So after this introduction, here's what you need to do:

  1. (if you haven't already,) go to ReSharper Options, then Code Inspection → Code Annotations, and press the Copy default implementation to clipboard button
  2. Create a file in any of your (shared) projects called Annotations.cs (or any other name)
  3. Paste the code from the clipboard, completely replacing anything that was previously in Annotations.cs
  4. Add the following definition at the end of the file:

Code:

/// <summary>
/// Indicates that IEnumarable, passed as parameter, is not enumerated.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NoEnumerationAttribute : Attribute
{
}

After you done this, all that's left to do is place the [NoEnumeration] attribute on the value argument, like this:

public static void VerifyArgumentIsNotNull<T>([NoEnumeration] this T value, string valueName) where T : class
{
    ....
}

And that's it! The warning will disappear!

Bonus:

There are 3 additional attributes you can use to decorate this method to make it even more useful: [NotNull], [ContractAnnotation] and [InvokerParameterName]. I recently describe what they do (and a short demo) in this issue for a similar API called LiteGuard.

Annotations are fun :)

like image 114
Igal Tabachnik Avatar answered Sep 30 '22 02:09

Igal Tabachnik