同名的静态和实例方法?

Posted

技术标签:

【中文标题】同名的静态和实例方法?【英文标题】:Static and Instance methods with the same name? 【发布时间】:2010-09-14 16:16:50 【问题描述】:

我有一个在 C# 中同时具有静态和非静态接口的类。同名和签名的类中是否可以有静态和非静态方法?

我尝试执行此操作时遇到编译器错误,但出于某种原因,我认为有一种方法可以执行此操作。我错了还是没有办法在同一个类中同时拥有静态和非静态方法?

如果这是不可能的,有没有一种很好的方法来实现这样的东西,可以通用地应用于任何情况?

编辑 从我收到的回复来看,很明显没有办法做到这一点。我将使用不同的命名系统来解决这个问题。

【问题讨论】:

您能否举例说明您可能希望在哪里执行此操作? 我不建议您依靠大小写差异来区分两种方法。真是个坏主意。您永远不应该有两种仅在情况下不同的方法:我保证您最终会调用错误的方法。 将方法重命名为不同的名称。依赖大小写是不安全的,特别是如果编译后的代码有可能被另一种不区分大小写的 .NET 语言使用。仅仅因为语言是区分大小写的,你就应该依靠这一事实来消除方法名称的歧义。 此代码只能在 C# 中编译。我的公司专门使用 C#,代码不可能被转换或使用另一种语言,所以在这种情况下我是安全的。 知道 Ball 与 BaII 或 LOOP 与 L00P 之间的区别是一回事,已经造成了足够的麻烦,知道 doSomething 与 DoSomething 之间的区别真的很棘手,在不知不觉中,你发现自己对每个案例进行评论,以便在下周再次查看时让其他程序员或您自己清楚。 【参考方案1】:

不,你不能。限制的原因是静态方法也可以从非静态上下文中调用,而无需预先添加类名(因此使用 MyStaticMethod() 而不是 MyClass.MyStaticMethod())。如果两者都有,编译器无法判断您要查找的内容。

你可以拥有同名的静态和非静态方法,但不同的参数遵循与方法重载相同的规则,它们只是不能具有完全相同的签名。

【讨论】:

我发现这个答案的逻辑有缺陷。我看不出为什么 C# 不能通过要求“this”来消除歧义。在这种情况下调用实例方法的令牌。另外,andasa 展示了静态方法和实例方法可以具有相同名称的方式。 没错,他们可能会进行某种类型的检查,如果发生冲突,默认情况下会选择静态方法,并要求这样做。用于访问实例方法。当然,在处理静态属性时这会变得很棘手,因为在方法的范围内,如果您的参数被命名为与您的静态/实例属性之一相同,那么您将不得不使用类名来指定静态版本,这个指定实例版本,如果没有,访问参数。对我来说,这听起来是一种很好的方式来发现很多难以找到的错误。 我认为默认情况下,所有来自非静态范围的调用都应该对非静态方法进行。如果你想要全局,那么你应该通过类名前缀来请求它。【参考方案2】:

实际上,有一种方法可以通过显式实现接口来实现这一点。这不是一个完美的解决方案,但在某些情况下它可以工作。

interface IFoo

    void Bar();


class Foo : IFoo

    static void Bar()
    
    

    void IFoo.Bar()
    
        Bar();
    

我在为 P/Invoke 调用创建包装类时有时会遇到这种情况。

【讨论】:

我这样做的确切原因是 P/Invoke 调用。谢谢:) 刚刚解决了这个问题,@Kamarey。显式接口实现必须没有访问修饰符,它始终是公共的。 在我的应用程序中执行(new Foo()).Bar(); 时出现错误:Member 'Foo.Bar()' cannot be accessed with an instance reference; qualify it with a type name instead. @T.Todua 是的,您需要将其称为 IFoo 才能做到这一点。您可以使用((IFoo)(new Foo())).Bar();IFoo foo = new Foo(); foo.Bar();【参考方案3】:

您可以从实例方法中调用静态方法,而无需指定类型名称:

class Foo

    static void Bar()
    
    

    void Fizz()
    
        Bar();
    

...所以不允许您拥有具有相同签名的静态方法和实例方法是有道理的。

你想完成什么?在不了解具体情况的情况下很难提出解决方法。我只是重命名其中一种方法。

【讨论】:

【参考方案4】:

C# 在这方面设计得并不好......

虽然您确实可能需要全局或非全局,但它应该默认选择一个,如果您想要另一个,那么您只需对其进行更多限定。

class Logger 
   public static Logger instance;

   public static void Log(string message) 
       instance.Log(message); // currently the compiler thinks this is ambiguous, but really its not at all.  Clearly we want the non-static method
   

   public void Log(string message) 

   

   public void DoStuff() 
      Log("doing instance stuff"); // this could be ambiguous, but in my opinion it should default to a call to this.Log()
      Logger.Log("doing global stuff"); // if you want the global qualify it explicitly
   

【讨论】:

【参考方案5】:

好的。 这个问题的根源在于,C# 不应该让您在不指定类型名称的情况下从实例方法调用静态方法。

其他完整的 OO 语言(如 Smalltalk)不允许这样做,而且这只会让了解对象的人感到困惑。 实例端和类(或静态)端之间的分离非常重要,并且使用一种会在这些细节上引起混淆的语言......不是一个好主意......但是我们期望的典型类型来自 MS。

阿德里安

【讨论】:

您的帖子没有回答问题。请考虑为问题添加具体答案或添加评论以解释问题。 我理解反对票,因为它没有回答问题,但这确实是问题的原因。对于开发人员来说,在静态方法之前查看类名作为第一眼指示“是的,这是一个静态方法、属性、字段”等... 三年后,但我想说我很欣赏@Adrian 提出的观点,而不是那些完全不合时宜的贬义陈述,特别是:“C# 不应该让你打电话”,“但这是我们期望从 MS 获得的典型类型的东西。”第一点虽然是一个很好的观点,但不应作为事实陈述。 那些想要在 C# 中练习体面的对象架构和设计的人有祸了。像这样的小限制会增加复杂性并降低清晰度。类与实例不同,两者都应该能够毫无混淆地声明“Foo”。能够在实例方法中指定 Foo 而不是 Klass.Foo 的便利性优于正确性,这远被语言本身的冗长所淹没。不恰当地优化语言是 C++ 血统的悲惨历史的一部分。【参考方案6】:

你可以有同名的静态方法和实例方法,只要它们的声明在参数的数量或类型上不同。关于如何在一个类中拥有两个具有相同名称的实例方法的规则相同。

虽然从技术上讲,在静态方法与实例方法的情况下,它们已经因实例方法中隐含 this 参数的存在而有所不同,但这种差异不足以让编译器确定您要调用两者中的哪一个.

更新:我犯了一个错误。返回值不足以具有不同的签名。

【讨论】:

错误:只要它们的参数数量和/或类型不同。返回类型不会重载。

以上是关于同名的静态和实例方法?的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中方法和变量在继承中的覆盖和隐藏

在 Swift 3 中将类与同名的实例成员区分开来

java中的成员变量、类变量,成员方法、类方法各是啥,怎么区分,

python:当类属性、实例属性和方法都同名时会发生啥?

静态方法@staticmethod 属性方法@property

父类的静态方法能否被子类重写?静态属性和静态方法是否可以被继承?