【问题标题】:Overriding a method signature using virtual使用虚拟覆盖方法签名
【发布时间】:2012-10-19 01:01:48
【问题描述】:

众所周知,对类中的方法使用 virtual 关键字可以让我们在其派生的子类中覆盖它。但是,方法仍然必须坚持相同的签名,例如返回值、参数等。

问题:在 C# 中,我如何也可以覆盖签名?这可能吗?

谢谢。

【问题讨论】:

    标签: c#


    【解决方案1】:

    这是不可能的。不过,如果需要,您可以创建一个重载。

    编辑

    为了反对new,请考虑您有一个基础对象以及继承自它的基础对象的情况。通过将new 放在您尝试“更改”方法签名的方法之前,实际上是在浪费四次击键。

    public class Base {
        public string Foo () { return null; }
    }
    
    public class Inherited : Base {
        public new int Foo () { return 0; }
    }
    

    现在,Inherited 有两种方法:

    public string Foo () { return null; }
    public int Foo () { return 0; }
    

    您实际上并没有更改方法签名。因此,甚至不需要 new 关键字。没有它你会得到同样的效果:

    public class Inherited : Base {
        public int Foo () { return 0; }
    }
    

    new的用法是override a non-virtual member of a base class

    public class Base { 
        public string Foo () { return null; }
    }
    
    public class Inherited : Base {
        public new string Foo () { return "Something else..."; }
    }
    

    但是如果你不注意这个微妙之处,你会遇到这个问题。使用virtual,您将获得一个虚拟查找表,它将您的函数映射到正确的调用。使用new,您不会。如果您在需要Base 对象的地方传入Inherited(这当然可以),则Base 类的Foo() 将被调用!不是,Inherited“覆盖”Foo()

    这与覆盖虚拟成员的行为不同。

    public static class MyClass {
        public string MyMethod (Base @base) {
            return @base.Foo ();
        }
    }
    
    [Test]
    public void then_it_should_return_non_null () {
        var obj = new Inherited ();
        var result = MyClass.MyMethod(obj);  // obj will get upcasted to Base
        Assert.That (result, Is.EqualTo(obj.Foo ())); // Assert fails!
    }
    
    [Test]
    public void inherited_should_return_correct_value ()
    {
        var obj = new Inherited ();
        var result = obj.Foo ();  // will access the "new" method, hiding Base's implementation
        Assert.That (result, Is.Not.Null);  // Assert passes! 
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用 new 关键字隐藏旧的实现。但是,基类将无法看到它。

      class Base {
         public string Foo() { }
      }
      
      class Sub : Base {
         new public int Foo() { }
      }
      

      new 仅在调用签名相同时才需要。

      【讨论】:

      • 不过,这不会改变签名。
      • @JamesD'Angelo 是的,它可以更改签名。
      • 它不会改变签名。它覆盖了一个非虚拟类成员。
      • VS 中的快速健全性检查给了我一个警告:“成员 'foo.bar()' 不会隐藏继承的成员。不需要新关键字。”
      • @JamesD'Angelo 他们是公开的吗?
      【解决方案3】:

      此时您只是在制作一种新方法。但是,如果你想简单地创建一个带有新方法签名的新方法,然后调用 base.OtherMethod(param1, param2)... 你可以。

      我想说的是,如果你打算创建一个与基类同名但签名不同的方法但你仍然想只调用基类,那么你就可以了。

      例如:

      // In base class - note, the "virtual" isn't necessary.
      public virtual void PostMessage(string message, DateTime entryDate) { ... }
      

      然后你想……“哦,伙计,我希望这个基类有一个不需要日期的方法的重载……我该怎么办?!”

      // In your sub-class.
      public void PostMessage(string message)
      {
          base.PostMessage(message, DateTime.Now);
      }
      

      【讨论】:

      • 感谢您的评论。我看到你在说什么,但没有得到最后一条语句“然后调用 base.OtherMethod(param1, param2)... 你可以。”你能给我一些想法吗?
      【解决方案4】:

      您正在谈论创建一个新方法。如果名称相同,但参数不同(返回类型和参数的类型和参数个数),您实际上是在重载。

      【讨论】:

        猜你喜欢
        • 2012-06-19
        • 2012-06-04
        • 2014-03-18
        • 2012-10-26
        • 2011-05-21
        • 1970-01-01
        • 1970-01-01
        • 2013-01-15
        • 1970-01-01
        相关资源
        最近更新 更多