Wednesday, August 30, 2006

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?

posted on Wednesday, August 30, 2006 4:17:27 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]

kick it on DotNetKicks.com