Home > Software design >  Static method in generic class causes CA1000 warning
Static method in generic class causes CA1000 warning

Time:02-07

I'm working on a library to manage objects (Animals in my sample code). I have a base class named Animal and a generic class named SpecificAnimal. I also have Dog, Cat etc. which are implemented with the SpecificAnimal class.

If a user wants to create a dog, it is as simple as:

            var myDog = new Dog()
            {
                Name = "Rover",
                Age = 3
            };
            myDog.Add();

The class hierarchy looks like this:

Animal Class

    public abstract class Animal
    {
        public static Animal GetByName(string animalName)
        {
            // Code that can read any kind of animal from a database
            // and create an instance of the correct type 
            throw new NotImplementedException();
        }

        public static Animal GetById(int animalId)
        {
            // Code that can read any kind of animal from a database
            // and create an instance of the correct type 
            throw new NotImplementedException();
        }

        public string Name { get; set; } = string.Empty;

        public int Age { get; set; }

        public void Add()
        {
            //  Add this Animal to the database
        }

        public void Update()
        {
            // Update this animal
        }
    }

Generic SpecificAnimal class

    public abstract class SpecificAnimal<T> : Animal where T : SpecificAnimal<T>
    {
        public static string Genus { get; protected set; } = String.Empty;

        public new static T GetByName(string animalName)
        {
            // Code that can read an object of type T from a database
            return (T)Animal.GetByName(animalName);
        }

        public new static T GetId(int animalId)
        {
            // Code that can read an object of type T from a database
            return (T)Animal.GetById(animalId);
        }
    }

Dog class

    public class Dog : SpecificAnimal<Dog>
    {
        public Dog()
        {
            Genus = "Canis";
        }

        //  Dog specific properties and methods
    }

This code is working and (in my opinion) is easy for the consumer of the library to use.

My problem is that the static properties and methods in the SpecificAnimal class generate the warning:

CA1000: Do not declare static members on generic types

https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1000

The documentation for CA1000 says "Do not suppress..." but, it doesn't suggest a better solution. If I shouldn't have static members in a generic class, what should I be doing? The documentation says that static methods in a generic type are bad because of this awkward syntax:

var myDog = SpecificAnimal<Dog>.GetByName("Rover");

I agree but, my users should never do that. Although, I don't know of a way to prevent it.

Should I just suppress CA1000 or is there a better way?

CodePudding user response:

The warning exists because there's risk that the behavior might be different than the programmer expects. However, sometimes it's a useful pattern. I ran into this a few weeks ago when building a library.

Let's look at a more simplified example:

void Main()
{
    Baz<string>.Counter  ;
    Baz<int>.Counter  ;
    Console.WriteLine(Baz<object>.Counter);
}

public abstract class Foo
{
    public static int Counter { get; set; }
}

public class Baz<T> : Foo
{
    
}

What is output? It's easy to think the output would be 0 because Baz<object> is a different closed generic type than Baz<string> or Baz<int>. In fact, the output is 2 because both post increment operations affect the same static variable.

CodePudding user response:

The property can be rewritten as in the example.

public abstract class SpecificAnimal<T> : Animal where T : SpecificAnimal<T>
{
    public virtual string Genus { get; } = String.Empty;
}

public class Dog : SpecificAnimal<Dog>
{
    public override string Genus { get; } = "Canis";
}

Note that implementing the static new method does not work in the same way as inheritance.

  •  Tags:  
  • Related