21

在 C# 中,我有基类 Product 和派生类 Widget。

产品包含一个静态方法 MyMethod()。

我想从静态方法 Widget.MyMethod() 调用静态方法 Product.MyMethod()。

我不能使用 base 关键字,因为它只适用于实例方法。

我可以显式调用 Product.MyMethod(),但如果我稍后将 Widget 更改为从另一个类派生,我必须修改该方法。

C# 中是否有一些类似于 base 的语法允许我从派生类的静态方法调用基类的静态方法?

4

9 回答 9

21

static方法基本上是一种从面向对象概念中回退的方法。结果,它们在继承层次结构中不是很灵活,并且不可能直接做这样的事情。

我能想到的最接近的东西是using指令。

using mybaseclass = Namespace.BaseClass;

class MyClass : mybaseclass {

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

}
于 2009-03-02T17:27:35.807 回答
4

可以办到:

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

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

可用于单元测试受保护的静态方法(例如)。

于 2014-09-23T22:38:49.487 回答
4

可以,但我不推荐。

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);
    }
}
于 2009-03-02T17:41:55.817 回答
4

使用反射调用静态方法与调用实例方法完全相同,只是您为实例传递了 null。您需要 FlattenHierarchy 因为它是在祖先中定义的。

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

进一步的阅读和思考让我提出了与其他回答相同的问题:为什么要使用这样的静态方法?您是否尝试进行函数式编程,如果是,为什么不使用 lambda 表达式呢?如果您想要具有共享状态的多态行为,实例方法会更好。

于 2012-07-03T10:55:39.337 回答
2

首先也是最重要的,如果您担心重新设置类的父级,那么您可能做错了继承。继承应该用于建立“is-a”关系,而不是简单地促进代码重用。如果您需要单独重用代码,请考虑使用委托,而不是继承。我想你可以在子类型和它的父类型之间引入一个中间类型,但我会让这种可能性驱动我的设计。

其次,如果您需要使用基类中的功能但扩展它并且用例调用静态方法,那么您可能需要考虑使用一些外部类来保存该功能。在我看来,这方面的经典案例是工厂模式。实现工厂模式的一种方法是通过工厂方法,这是一个类的静态方法,用于构造该类的实例。通常构造函数是受保护的,因此工厂方法是从外部构建类的唯一方法。

在继承层次结构中重用工厂方法的一种方法是将公共代码放在受保护的方法中并从工厂方法调用该方法,而不是直接从子类型工厂方法调用基类工厂方法。更好的实现可能使用相同的技术,但将工厂方法移动到工厂类并使用构造函数逻辑(现在是内部的,而不是私有的),可能与初始化方法结合使用来创建对象。如果您继承的行为是类外部的(解密/验证/等),您可以在工厂内使用共享方法(或组合)以允许在工厂方法之间重用。

在不知道您使用静态方法的目标的情况下,很难给您一个准确的方向,但希望这会有所帮助。

于 2013-01-07T14:08:41.423 回答
1

静态方法不是多态的,所以你想做的事情是不可能的。

试图找到一种将静态方法视为多态的方法是可能的,但很危险,因为语言本身不支持它。

一些建议:

于 2009-03-02T17:35:23.277 回答
0

静态方法是“类级”方法。它们旨在成为适用于特定类的所有实例的方法。因此,此方法的继承没有意义,因为它会改变应用于类实例的含义。例如,如果您正在循环通过一组产品(一些是 Widget,一些不是)并在每个产品上调用 MyMethod,那么被调用的方法将由类的实例确定。这违反了静态方法的目的。

您可以通过根本不使用静态方法来更干净地执行您想要的操作,因为在您的示例中,MyMethod 似乎不适用于 Product 的所有实例。但是,您可以通过使用像“IMyMethod”这样的接口类来实现您所描述的相同效果。这种方法仍然没有使用静态方法。我想我没有看到需要静态方法。为什么要使用静态方法开始?

于 2009-03-02T23:05:33.857 回答
0

考虑到静态方法不应该在实例数据中中继......你应该有一个静态的“MyMethod”,它根据参数或类似的东西表现不同。

请记住,在一个类中定义的静态方法只是对代码进行排序的一种方式......但如果将该方法放在其他地方也是一样的......因为它不会中继放置它的对象。

编辑:我认为您最好的选择是明确使用 Product.MyMethod ...如果您认为...您的 Widget 更改其基类的可能性不大...在这种情况下,这只是一个小改动在代码中。

于 2009-03-02T17:31:29.603 回答
0

这很简单。比使用别名、反射等要简单得多。也许在 .NET、IDK 的新添加中它变得更容易了,但这工作得非常好。与实例方法一样,访问基类方法不需要base使用,它是可选的,通常在继承和基类具有相同名称的方法时需要。即使没有base关键字,您也可以访问基类的静态方法,就好像它们在您调用的类中一样。我只在从派生类的静态方法调用基本静态方法时测试了这一点。如果您从实例方法调用静态方法,可能无法正常工作。

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();            
    }
}
于 2012-12-14T22:01:31.507 回答