UPDATE: It turns out that this was in fact a bug that has been corrected by Visual Studio 2005 Service Pack 1. Thanks to David Kean for the information. A full list of bugs in Managed Code Analysis bugs that are fixed by the service pack is available here.
In the comments section of my
"Getting a little more graceful with generics" post from the other day, a reader
brought this to my attention:
"When the line
static void DoSomethingWithList...
is changed to
public static void DoSomethingWithList...
and Code Analysis is run, it results in a CA1004 Microsoft.Design Warning 'GenericMethodsShouldProvideTypeParameter'"
In essence, when made visible to other types, the Code Analysis in Visual Studio
Team System flags this method with a warning. Ugh! But, after examining the warning
carefully, I'm not sure that the method is at fault. For reference, the documentation
of this warning is on MSDN at
http://msdn2.microsoft.com/en-us/library/ms182150.aspx.
In the documentation, the cause of this warning reads: "The parameter signature
of an externally visible generic method does not contain types that correspond to
all the type parameters of the method." In other words, this rule is in place to
prevent code like this:
public static void GenericMethod<T>();
In the above declaration, there isn't a parameter (or return type) that uses
the type parameter, T. To satisfy the rule, T has to be used as the type of a parameter
or as the return type like this:
public static void GenericMethod<T>(T arg);
or:
public static T GenericMethod<T>();
In our case, we're using T in the method signature but not directly as a parameter
type or the return type. Instead, we're using it to declare a generic type like
this:
public static void GenericMethod<T>(List<T> arg);
Is this in violation of the rule? Well, yes -- if you read the cause of the warning
in a very strict sense. But, consider the rule description:
"Inference is how the type argument of a generic method is determined by
the type of argument passed to the method, instead of by the explicit specification
of the type argument. To enable inference, the parameter signature of a generic
method must include a parameter that is of the same type as the type parameter for
the method. In this case, the type argument does not have to be specified. When
using inference for all type parameters, the syntax for calling generic and non-generic
instance methods is identical. This simplifies the usability of generic methods."
For a moment, ignore the horrendous bit of wording used in the description ("how
the type argument of a generic method is determined by the type of argument passed
to the method") and recognize that the purpose of this rule is to enforce the fact
that publicly visible generic methods should be declared in a way that allows them
to be called using type inference. For those that are unclear on what type inference
is as it relates to generic methods, check out my
previous post.
So, this rule is in place to ensure that type inference works for public generic
methods. However, the code that we're compiling clearly *does* allow type inference
to work. Given this declaration:
public static void GenericMethod<T>(List<T> arg);
I can call using type inference like this and it will compile fine:
GenericMethod(new List<string>);
GenericMethod(new List<int>);
The problem is that the rule doesn't consider the type arguments of any generic
types in the method signature when verifying that all of the method's type parameters
are used. However, it appears that the C# compiler does (so does the VB compiler).
This smells like a bug to me. Comments? Opinions? Flames?