0

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

例如:

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();
       }
    }
}
4

8 回答 8

8

你不能越权。覆盖替换原来的(从调用者的角度来看)。被覆盖的方法可以调用基类,但你不能在外部调用。

于 2011-03-10T20:34:20.003 回答
3

@James 是对的。为了建立他的答案,由于您可以从被覆盖的版本中调用基本版本,因此您可以向方法中发送某种标志来告诉它是执行自己的实现还是被覆盖的实现。像这样的东西:

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

为了使其工作,您还必须将该标志作为基本标志的参数,但您可以在那里忽略它。不优雅,也许非常丑陋,但可以满足您的需求。

于 2011-03-10T20:39:00.370 回答
1

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

于 2011-03-10T20:37:58.207 回答
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()
     }
  }
}
于 2011-03-10T20:43:51.543 回答
0

如果var item = new A(),它将调用A.Foo()

于 2011-03-10T20:35:40.603 回答
0

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

于 2011-03-10T20:38:06.560 回答
0

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

于 2011-03-10T20:40:59.740 回答
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");
    }
}

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

于 2011-03-10T20:43:00.027 回答