如何覆盖虚方法,但仍然在C#中调用基类版本

时间:2011-03-10 20:32:47

标签: c# types casting upcasting

我有一个简单的类层次结构,我有一个覆盖的虚方法。但在某些调用中我想调用此方法的基类版本而不是虚方法。

例如:

public class A {
    public virtual void Foo() {...}
}

public class B : A {
    public override void Foo() {...}
}

public class Program {
    public void SomeMethod()
    {
       ...

       //  ListofA is type IEnumerable<A>
       foreach (var item in ListofA)
       {
           // I want this to call A.Foo(), rather than B.Foo()
           // But everything I've tried, which has really just been casting, has resulted in B.Foo()
           item.Foo();
       }
    }
}

8 个答案:

答案 0 :(得分:8)

你无法覆盖。覆盖替换原始(从呼叫者的角度来看)。重写方法可以调用基数,但不能从外部调用。

答案 1 :(得分:3)

@James是对的。为了建立他的答案,因为你可以从被覆盖的那个调用基本版本,你可以在方法中发送某种标志来告诉它是执行自己的实现还是重写它。像这样:

public override void Foo(bool useBaseImplementation)
{
    if(useBaseImplementation)
    {
        base.Foo(useBaseImplementation);
    }
    else
    {
        //other stuff here
    }
}

为了使它能够工作,你必须将旗帜作为基础参数的参数,但你可以在那里忽略它。不优雅,也许是彻头彻尾的丑陋,但做到了你正在寻找的东西。

答案 2 :(得分:1)

如果是这种情况,那么你想要的实际上不是覆盖;你应该重新考虑你的设计。如果在重新定义中使用override代替new,则该方法不会是多态的,但同样,这也是高度指示有缺陷的设计。您还需要foreach (A item in ListofA)

答案 3 :(得分:1)

我不喜欢我的解决方案,因为它有点抽象,但也许你可以做以下事情:

public class A {
  public virtual void Foo() {...}
}

public class B : A {
  public override void Foo() {...}
  public override void parentFoo(){
    base.Foo();
  }
}

public class Program {
  public void SomeMethod(){
    ...

     //  ListofA is type IEnumerable<A>
     foreach (var item in ListofA){
       item.Foo(); //calls B.Foo()
       item.parentFoo(); //calls B.parentFoo() == A.Foo()
     }
  }
}

答案 4 :(得分:0)

如果var item = new A(),则会调用A.Foo()

答案 5 :(得分:0)

你可以使用base关键字在类中调用基本实现,但如果你试图从其他类调用它,我很确定你在你的代码中违反Liskov替换原则,如任何子类shoudl为虚拟方法提供了这样一种实现,可以完全替代超类。  重新审视您的设计。

答案 6 :(得分:0)

使用new而不是覆盖可以实现这一点。 这里有很好的解释:http://msdn.microsoft.com/en-us/library/ms173153%28v=vs.80%29.aspx

答案 7 :(得分:0)

一种可能的解决方法是不将方法设为虚拟,而是使用new关键字替换它:

   class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>
        {
            new B(),
            new B(),
            new B(),
            new B()
        };

        foreach (A a in list)
        {
            a.Foo();
        }

        foreach (B b in list)
        {
            b.Foo();
        }

        Console.ReadLine();
    }
}

public class A
{
    public void Foo()
    {
        Console.WriteLine("Base");
    }
}

public class B : A
{
    public new void Foo()
    {
        Console.WriteLine("Derived");
    }
}

如果您使用的引用类型为B,则只会调用B.Foo()实现。我不鼓励你这样做,因为我从来没有遇到new关键字有意义的情况。