【问题标题】:Creating an object of the type a static method is called on in an inheritance chain in C#在 C# 的继承链中创建一个静态方法类型的对象
【发布时间】:2009-12-04 19:34:42
【问题描述】:

我正在尝试在 C# 中做这样的事情

public class ParentClass {
  public static ParentClass GetSomething()
  {
    var thing = new // ?????
    return thing;
  }
}

public class ChildClass : ParentClass {
}

然后我希望能够像这样调用子类的静态方法:

ChildClass blah = ChildClass.GetSomething();

例如在子类上调用静态方法时,我想实例化子类的一个实例。但我只想要在父级上定义的静态方法。这是可能吗?我会很高兴:

ChildClass blah = (ChildClass) ChildClass.GetSomething();

谢谢!

【问题讨论】:

    标签: c# inheritance syntax static types


    【解决方案1】:

    这闻起来很糟糕,但你可以这样做:

    public class ParentClass {
        public static T GetSomething<T>() where T : ParentClass, new() {
            return new T();
        }
    }
    

    用法:

    ParentClass parent = ParentClass.GetSomething<ParentClass>();
    ChildClass child = ChildClass.GetSomething<ChildClass>();
    

    这也是合法的:

    ParentClass parent = ChildClass.GetSomething<ParentClass>();
    

    这导致了这种气味(是的,它只是编译为ParentClass parent = ParentClass.GetSomething&lt;ParentClass&gt;(),但它仍然有气味)。

    【讨论】:

    • 唯一难闻的地方是调用无参数构造函数 IMO - 在实际代码中可能有解决方法。使其成为泛型方法的基本前提是合理的:)
    • 感谢您的回答。我觉得它位于泛型的某个地方,但我对 C# 还很陌生,而且我一直在学习它……有人可以推荐一个很好的泛型介绍吗?事实上,还有一个用于一般 C# 最佳实践的方法!我将尝试将这些解决方案应用到我的实际班级结构中,看看什么效果最好(显然以上是完全简化的)。再次感谢!
    • @vitch:Jon Skeet 的书中有一章非常好介绍泛型(如果您在 C# 开发方面进展顺利,我强烈推荐)。至于“C# 最佳实践”,我认为 Effective C# 和 More Effective C# (Bill Wagner) 以及框架设计指南 (Microsoft) 都很好。 (Jon 的书在这方面也不错,但不如上述文本那么明确。)
    • 谢谢 Jason,我看看能不能掌握它们...我阅读了 MSDN 对泛型的介绍,看起来它们实际上很简单,这只是一个学习一点的案例一点语法:)
    • @vitch:是的,语法很简单(我们这里不是在谈论 C++ 样式模板,它们完全不同)。艺术在于学习何时使用泛型。 :-)
    【解决方案2】:

    您不能“覆盖”静态方法。但是您可以使用泛型来告诉 ParentClass 您实际指的是哪个派生类。它有点难看,但它有效:

    class ParentClass<T> where T : ParentClass<T>, new()
    {
        public static T GetSomething()
        {
            T thing = new T();
            return thing;
        }
    }
    
    class ChildClass : ParentClass<ChildClass>
    {
    }
    

    测试:

    ChildClass x = ChildClass.GetSomething(); // works
    

    【讨论】:

    • 感谢您的回答。看起来这正是我在演示代码中所要求的语法......我会将它集成到实际的代码库中,并让你知道它是如何工作的:)
    • 其实在类级别和方法级别定义有什么区别呢?这似乎是两种解决方案之间的区别......
    • 这个解决方案的工作方式如下:在ChildClass.GetSomething(); 编译器可以看到 ChildClass 是从 ParentClass 继承的,参数 T = ChildClass。 T 的这个值随后用于声明GetSomething() 方法的返回类型。因此,您无需在其他任何地方指定返回类型。优点:调用方法的语法更简单。缺点:代码更复杂,灵活性更低。
    • 区别在于本例中BaseClass中的T和方法返回类型中的T必须相同。
    • 感谢您的回答...我在这里看到了同样的解释:stackoverflow.com/questions/1853414/… - 为整个类或基于每个方法设置 T 的类型...
    【解决方案3】:

    这一行:

    ChildClass blah = ChildClass.GetSomething();
    

    被编译为 与此行完全相同的 IL

    ChildClass blah = ParentClass.GetSomething();
    

    (当ChildClass 没有声明自己的GetSomething 方法时)。

    我更喜欢:

    ChildClass blah = ParentClass.GetSomething<ChildClass>();
    

    这就像你的铸造版本,但尖括号和类型名称在方法名称之后而不是在方法名称之前:)(基本上是 Jason 的建议,现在我已经看到了!)

    不过,现在这在某种程度上独立于 ParentClass - 您可以在任何有用的地方定义它:

    public static class FactoryUtil
    {
        public static T CreateInstance<T>() where T : ParentClass
        {
            ...
        }
    }
    

    ...或者您可以在需要的地方提供工厂作为依赖项,从而使事情更具可测试性,可能...

    【讨论】:

    • 感谢您的回答和澄清...我还要考虑工厂方法,我现在需要回顾一下我的实际代码库并尝试找出应用的最佳方式这个新发现的知识!
    【解决方案4】:

    C# 不允许您覆盖静态方法。

    不过,没有什么能阻止您在 ChildClass 上重新定义一个隐藏 ParentClass 方法的新静态方法。这样做会有帮助吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-10
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 2011-12-27
      • 2013-10-20
      相关资源
      最近更新 更多