Code Analysis Warning CA1004 with generic method

2019-07-13 11:06发布

问题:

I have the following generic method:

// Load an object from the disk
public static T DeserializeObject<T>(String filename) where T : class
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

    try
    {
        TextReader textReader = new StreamReader(filename);
        var result = (T)xmlSerializer.Deserialize(textReader);
        textReader.Close();
        return result;
    }
    catch (FileNotFoundException)
    { }

    return null;
}

When I compile I get the following warning:
CA1004 : Microsoft.Design : Consider a design where 'MiscHelpers.DeserializeObject(string)' doesn't require explicit type parameter 'T' in any call to it.

I have considered this and I don't know a way to do what it requests with out limiting the types that can be deserialized. I freely admit that I might be missing an easy way to fix this.

But if I am not, then is my only recourse to suppress this warning? I have a clean project with no warnings or messages. I would like to keep it that way.

I guess I am asking "why this is a warning?" At best this seems like it should be a message. And even that seems a bit much. Either it can or it can't be fixed. If it can't then you are just stuck with the warning with no recourse but suppressing it. Am I wrong?

回答1:

Since you're using T in the return type, this is a false positive.

It was fixed in Code Analysis for VS2010.



回答2:

This is a fair usage warning. The trouble is that the compiler cannot deduce the type argument from the method call. The left side of the assignment statement is not considered. For example:

  class Example {
    public T Method1<T>() {
      return default(T);
    }
    public T Method2<T>(T arg) {
      return arg;
    }

    public void Test() {
      int value1 = Method1();       // CS0411
      int value2 = Method1<int>();  // OK
      int value3 = Method2(42);     // Inferred, no problems
    }
  }

Note how Method1 must be called by explicitly specifying the type argument. That's okay but makes it harder to use the method. That's why CA1002 is a usage warning. Method2 doesn't have this problem, the compiler can automatically infer that the type argument must be an integer from the argument type.

Two possible ways you could apply this to your method:

public static void DeserializeObject<T>(String filename, out T result) where T : class {
  // etc..
}

or

public static T DeserializeObject<T>(String filename, T defaultValue) where T : class {
  // etc...
}

Not so sure these are better solutions, although swallowing exceptions and returning null doesn't win prizes either. It is up to you to make the call.