Static members and interfaces

2019-05-10 12:18发布

问题:

I just went through a handful of SO questions on this topic and found out that this is (currently?) not possible to define static members in interfaces or make static methods virtual. I'm now struggling with a situation. Let me try to depict it with a simple example:

I have an interface named say IAnimal with the following definition:

interface IAnimal {
    ...
    int Chromosomes {get; } //should ideally be static, but that's not allowed!
    ...
}

Then I have a base class Animal that implements IAnimal and provides implementation of some methods common to all animals:

abstract class Animal : IAnimal { 
    ...
    public abstract int Chromosomes {get; } //necessary becuz of IAnimal
    ...
}

Below this I then have Dog, Cat and Zebra classes that inherit from Animal and provide concrete implementations of this property for their species.

Now the problem: These classes are discovered at runtime (through Assembly.LoadFile() becuz of the pluggable-modules). The discovered classes are kept in a List<System.Type> that we later use to create concrete dogs and cats. The input parameter for the creation of an animal is chromosomes number, so for example they'll ask: Create an animal of the type that has 72 chromosomes. So I need to somehow get the Chromosome property's value of each Type in the List and return the first matching Type.

Since Chromosomes is not static (if it were, I could easily run a static member of a given Type), am I forced to create a temporary object of each type and then call Chromosomes with it, or is there a better way? All the elements in my List are guarenteed to be IAnimal if that is of help.

回答1:

Basically the C# type system isn't geared up for this. It's not often a problem, but when it does come up it's a pain :( Some options you might want to think about, all of which start off by removing the existing property:

  • Create a separate type hierarchy for the types themselves (DogType, AnimalType etc) which could also be responsible for creating instances if that's useful. That tends to be a bit of a pain.
  • Add an attribute to the type, indicating the number of chromosomes - this only works when the value is constant, of course. You can then find the attribute value with reflection. It won't be enforced at compile-time though.
  • Make a static property which can be invoked with reflection, and then add unit tests to ensure that every type which implements the interface also has the static property