C#: How do I call a static method of a base class

2020-02-10 02:52发布

问题:

In C#, I have base class Product and derived class Widget.

Product contains a static method MyMethod().

I want to call static method Product.MyMethod() from static method Widget.MyMethod().

I can't use the base keyword, because that only works with instance methods.

I can call Product.MyMethod() explicitly, but if I later change Widget to derive from another class, I have to revise the method.

Is there some syntax in C# similar to base that allows me to call a static method from a base class from a static method of a derived class?

回答1:

static methods are basically a method to fallback from object oriented concepts. As a consequence, they are not very flexible in inheritance hierarchies and it's not possible to do such a thing directly.

The closest thing I can think of is a using directive.

using mybaseclass = Namespace.BaseClass;

class MyClass : mybaseclass {

  static void MyMethod() {  mybaseclass.BaseStaticMethod();  }

}


回答2:

It can be done, but I don't recommend it.

public class Parent1
{
    public static void Foo()
    {
        Console.WriteLine("Parent1");
    }
}

public class Child : Parent1
{
    public new static void Foo()
    {
        Type parent = typeof(Child).BaseType;
        MethodInfo[] methods = parent.GetMethods();
        MethodInfo foo = methods.First(m => m.Name == "Foo");
        foo.Invoke(null, null);
    }
}


回答3:

Calling a static method using reflection is exactly the same as calling an instance method except that you pass null for the instance. You need FlattenHierarchy because it's defined in an ancestor.

var type = assy.GetType("MyNamespace.MyType");
MethodInfo mi = type.GetMethod("MyStaticMethod", 
  BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
mi.Invoke(null, null);

Further reading and thinking leaves me asking the same questions as others who have responded: why use static methods like this? Are you trying to do functional programming, and if so why not use lambda expressions instead? If you want polymophic behaviours with shared state, instance methods would be better.



回答4:

It can be done:

public class Parent1
{
    protected static void Foo()
    {
        Console.WriteLine("Parent1");
    }
}

public class Child : Parent1
{
    public static void Foo()
    {
        return Parent1.Foo();
    }
}

Can be useful for unit testing protected static methods (for example).



回答5:

First and foremost, if you're worried about re-parenting a class, then you're probably doing inheritance wrong. Inheritance should be used to establish "is-a" relationships, not simply foster code reuse. If you need code re-use alone, consider using delegation, rather than inheritance. I suppose you could introduce an intermediate type between a sub-type and its parent, but I would let that possibility drive my design.

Second, if you need to use functionality from the base class but extend it AND the use case calls for a static method, then you might want to consider using some external class to hold the functionality. The classic case for this in my mind is the Factory pattern. One way to implement the Factory pattern is through Factory Methods, a static method on a class that constructs an instance of that class. Usually the constructor is protected so that the factory method is the only way to build the class from outside.

One way to approach re-use with Factory Methods in an inheritance hierarchy would be to put the common code in a protected method and call that method from the Factory Method rather than directly call the base class Factory Method from a sub-types Factory Method. A better implementation might use the same technique but move the Factory Methods to a Factory class and use the constructor logic (internal now, not private), perhaps in conjunction with an initialization method(s), to create the object. If the behavior you are inheriting is external from the class (decryption/validation/etc), you can use shared methods (or composition) within the Factory to allow re-use between the Factory methods.

Without knowing the goal of your use of static methods it's difficult to give you an exact direction, but hopefully this will help.



回答6:

Static methods are not polymorphic, so what you want to do is impossible.

Trying to find a way to treat static methods as polymorphic is possible but dangerous, because the language itself doesn't support it.

Some suggestions:

  • Reflection
  • Aliasing the base class (such as Mehrdad's example)


回答7:

Having into account that a Static method shoudn't relay in instance data... you should have a static "MyMethod" that behaves diferent based on a parameter or something like that.

Remember that the static method defined in one class is just a way to order your code... but it is the same if that method is placed elsewhere... because it don't relay on the object where it is placed.

EDIT: I think your best choise is to use Product.MyMethod explicitly... If you think it... it should't be probable that your Widget change its base clase... and also in that case it is a minor change in code.



回答8:

Static methods are "Class-Level" methods. They are intended to be methods that apply to all instances of a specific class. Thus, inheritance of this method does not make sense as it would change the meaning to apply to instances of the class. For instance, if you were looping through a collection of Products (some of Widget, some not) and called MyMethod on each Product then the method that was called would be determined by the instance of the class. This violates the purpose of static methods.

You can probably do something like you want more cleanly by simply not using static methods at all, because in your example it does not seem like MyMethod applies to all instances of Product. However, you can achieve the same affect you are describing by using an interface class like ‘IMyMethod’. This approach is still not using a static method. I guess I’m not seeing a need for a static method. Why do you want to use a static method to begin with?



回答9:

It's very simple. Much simpler than using aliasing, reflections, etc. Maybe it's been made easier in newer additions of .NET, IDK, but this works perfectly fine. Just like with instance methods, accessing base methods doesn't require base be used, it is optional, usually necessary when the inheriting and base class have a method of the same name. Even without the base keyword, you can access the static methods of a base class as if they were in the class you are calling from. I only tested this when calling a base static method from a derived class's static method. Might not work if you are calling from an instance method to a static method.

public class BaseThings
{
    protected static void AssertPermissions()
    {
        //something
    }
}

public class Person:BaseThings
{
    public static void ValidatePerson(Person person)
    {
        //just call the base static method as if it were in this class.
        AssertPermissions();            
    }
}