C# 如何调用 base.base.method()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2323401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call base.base.method()?
提问by AZ.
// Cannot change source code
class Base
{
public virtual void Say()
{
Console.WriteLine("Called from Base.");
}
}
// Cannot change source code
class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");
base.Say();
}
}
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
class Program
{
static void Main(string[] args)
{
SpecialDerived sd = new SpecialDerived();
sd.Say();
}
}
The result is:
结果是:
Called from Special Derived.
Called from Derived. /* this is not expected */
Called from Base.
从特殊派生调用。
从派生调用。/* 这不是预期的 */
从 Base 调用。
How can I rewrite SpecialDerived class so that middle class "Derived"'s method is not called?
如何重写 SpecialDerived 类,以便不调用中间类“Derived”的方法?
UPDATE:The reason why I want to inherit from Derived instead of Base is Derived class contains a lot of other implementations. Since I can't do base.base.method()
here, I guess the best way is to do the following?
更新:我想从 Derived 继承而不是 Base 的原因是 Derived 类包含很多其他实现。既然我不能在base.base.method()
这里做,我想最好的方法是做以下事情?
// Cannot change source code
// 无法更改源代码
class Derived : Base
{
public override void Say()
{
CustomSay();
base.Say();
}
protected virtual void CustomSay()
{
Console.WriteLine("Called from Derived.");
}
}
class SpecialDerived : Derived
{
/*
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
*/
protected override void CustomSay()
{
Console.WriteLine("Called from Special Derived.");
}
}
回答by rh.
You can't from C#. From IL, this is actually supported. You can do a non-virt call to any of your parent classes... but please don't. :)
你不能从 C#。从 IL 来看,这实际上是受支持的。您可以对任何父类进行非虚拟调用……但请不要。:)
回答by JoshJordan
The answer (which I know is not what you're looking for) is:
答案(我知道这不是你要找的)是:
class SpecialDerived : Base
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
The truth is, you only have direct interaction with the class you inherit from. Think of that class as a layer - providing as much or as little of it or its parent's functionality as it desires to its derived classes.
事实是,您只能与您继承的类直接交互。将该类视为一个层 - 为其派生类提供尽可能多或尽可能少的它或其父级的功能。
EDIT:
编辑:
Your edit works, but I think I would use something like this:
您的编辑有效,但我想我会使用这样的东西:
class Derived : Base
{
protected bool _useBaseSay = false;
public override void Say()
{
if(this._useBaseSay)
base.Say();
else
Console.WriteLine("Called from Derived");
}
}
Of course, in a real implementation, you might do something more like this for extensibility and maintainability:
当然,在实际实现中,为了可扩展性和可维护性,您可能会做更多类似的事情:
class Derived : Base
{
protected enum Mode
{
Standard,
BaseFunctionality,
Verbose
//etc
}
protected Mode Mode
{
get; set;
}
public override void Say()
{
if(this.Mode == Mode.BaseFunctionality)
base.Say();
else
Console.WriteLine("Called from Derived");
}
}
Then, derived classes can control their parents' state appropriately.
然后,派生类可以适当地控制其父类的状态。
回答by Eric Lippert
This is a bad programming practice, and not allowed in C#. It's a bad programming practice because
这是一种糟糕的编程习惯,在 C# 中是不允许的。这是一种糟糕的编程习惯,因为
The details of the grandbase are implementation details of the base; you shouldn't be relying on them. The base class is providing an abstraction overtop of the grandbase; you should be using that abstraction, not building a bypass to avoid it.
To illustrate a specific example of the previous point: if allowed, this pattern would be yet another way of making code susceptible to brittle-base-class failures. Suppose
C
derives fromB
which derives fromA
. Code inC
usesbase.base
to call a method ofA
. Then the author ofB
realizes that they have put too much gear in classB
, and a better approach is to make intermediate classB2
that derives fromA
, andB
derives fromB2
. After that change, code inC
is calling a method inB2
, not inA
, becauseC
's author made an assumption that the implementation details ofB
, namely, that its direct base class isA
, would never change. Many design decisions in C# are to mitigate the likelihood of various kinds of brittle base failures; the decision to makebase.base
illegal entirely prevents this particular flavour of that failure pattern.You derived from your base because you like what it does and want to reuse and extend it. If you don't like what it does and want to work around it rather than work with it, then why did you derive from it in the first place? Derive from the grandbase yourself if that's the functionality you want to use and extend.
The base might require certain invariants for security or semantic consistency purposes that are maintained by the details of how the base uses the methods of the grandbase. Allowing a derived class of the base to skip the code that maintains those invariants could put the base into an inconsistent, corrupted state.
大基的细节是基的实现细节;你不应该依赖他们。基类提供了基类之上的抽象;您应该使用该抽象,而不是构建旁路来避免它。
为了说明上一点的一个具体例子:如果允许,这种模式将是另一种使代码易受脆弱基类故障影响的方式。假设
C
派生自B
派生自A
。在代码中C
使用base.base
调用的方法A
。然后作者B
意识到他们在类中放置了太多的齿轮,B
更好的方法是制作B2
派生自A
,B
派生自 的中级类B2
。更改之后,代码 inC
调用的是 in 方法B2
,而不是 in方法A
,因为C
作者假设 的实现细节B
,即它的直接基类是A
,永远不会改变。C# 中的许多设计决策都是为了减轻各种脆弱的基础故障的可能性;将其设为base.base
非法的决定完全阻止了这种失败模式的这种特殊风格。你从你的基础派生出来,因为你喜欢它所做的,并希望重用和扩展它。如果您不喜欢它的功能并想解决它而不是使用它,那么您首先为什么要从它中衍生出来?如果这是您想要使用和扩展的功能,请自己从基础中获取。
出于安全性或语义一致性目的,基可能需要某些不变量,这些不变量由基如何使用大基的方法的细节来维护。允许基类的派生类跳过维护这些不变量的代码可能会使基类处于不一致、损坏的状态。
回答by Rajesh
You can also make a simple function in first level derived class, to call grand base function
您还可以在一级派生类中创建一个简单的函数,以调用宏基函数
回答by yoel halb
In cases where you do not have access to the derived class source, but need all the source of the derived class besides the current method, then I would recommended you should also do a derived class and call the implementation of the derived class.
如果您无权访问派生类源,但需要除当前方法之外的派生类的所有源,那么我建议您还应该做一个派生类并调用派生类的实现。
Here is an example:
下面是一个例子:
//No access to the source of the following classes
public class Base
{
public virtual void method1(){ Console.WriteLine("In Base");}
}
public class Derived : Base
{
public override void method1(){ Console.WriteLine("In Derived");}
public void method2(){ Console.WriteLine("Some important method in Derived");}
}
//Here should go your classes
//First do your own derived class
public class MyDerived : Base
{
}
//Then derive from the derived class
//and call the bass class implementation via your derived class
public class specialDerived : Derived
{
public override void method1()
{
MyDerived md = new MyDerived();
//This is actually the base.base class implementation
MyDerived.method1();
}
}
回答by Evk
Just want to add this here, since people still return to this question even after many time. Of course it's bad practice, but it's still possible (in principle) to do what author wants with:
只是想在这里添加这个,因为即使经过很多次人们仍然会回到这个问题。当然这是不好的做法,但仍然可以(原则上)做作者想要的:
class SpecialDerived : Derived
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
var ptr = typeof(Base).GetMethod("Say").MethodHandle.GetFunctionPointer();
var baseSay = (Action)Activator.CreateInstance(typeof(Action), this, ptr);
baseSay();
}
}
回答by Kruczkowski
Why not simply cast the child class to a specific parent class and invoke the specific implementation then? This is a special case situation and a special case solution should be used. You will have to use the new
keyword in the children methods though.
为什么不简单地将子类转换为特定的父类并调用特定的实现呢?这是一种特殊情况,应使用特殊情况解决方案。不过,您必须new
在 children 方法中使用关键字。
public class SuperBase
{
public string Speak() { return "Blah in SuperBase"; }
}
public class Base : SuperBase
{
public new string Speak() { return "Blah in Base"; }
}
public class Child : Base
{
public new string Speak() { return "Blah in Child"; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Child childObj = new Child();
Console.WriteLine(childObj.Speak());
// casting the child to parent first and then calling Speak()
Console.WriteLine((childObj as Base).Speak());
Console.WriteLine((childObj as SuperBase).Speak());
}
}
回答by Pavel
public class A
{
public int i = 0;
internal virtual void test()
{
Console.WriteLine("A test");
}
}
public class B : A
{
public new int i = 1;
public new void test()
{
Console.WriteLine("B test");
}
}
public class C : B
{
public new int i = 2;
public new void test()
{
Console.WriteLine("C test - ");
(this as A).test();
}
}
回答by Pierre
As can be seen from previous posts, one can argue that if class functionality needs to be circumvented then something is wrong in the class architecture. That might be true, but one cannot always restructure or refactor the class structure on a large mature project. The various levels of change management might be one problem, but to keep existing functionality operating the same after refactoring is not always a trivial task, especially if time constraints apply. On a mature project it can be quite an undertaking to keep various regression tests from passing after a code restructure; there are often obscure "oddities" that show up. We had a similar problem in some cases inherited functionality should not execute (or should perform something else). The approach we followed below, was to put the base code that need to be excluded in a separate virtual function. This function can then be overridden in the derived class and the functionality excluded or altered. In this example "Text 2" can be prevented from output in the derived class.
从之前的帖子中可以看出,人们可能会争辩说,如果需要绕过类功能,那么类架构就会出现问题。这可能是对的,但不能总是在大型成熟项目中重构或重构类结构。不同级别的变更管理可能是一个问题,但在重构后保持现有功能的运行并不总是一项微不足道的任务,尤其是在时间有限的情况下。在一个成熟的项目中,在代码重构后防止各种回归测试通过可能是一项艰巨的任务;经常会出现一些晦涩的“怪事”。在某些情况下,我们遇到了类似的问题,继承的功能不应该执行(或应该执行其他操作)。我们在下面遵循的方法,是将需要排除的基本代码放在一个单独的虚函数中。然后可以在派生类中重写此函数,并排除或更改功能。在此示例中,可以防止在派生类中输出“文本 2”。
public class Base
{
public virtual void Foo()
{
Console.WriteLine("Hello from Base");
}
}
public class Derived : Base
{
public override void Foo()
{
base.Foo();
Console.WriteLine("Text 1");
WriteText2Func();
Console.WriteLine("Text 3");
}
protected virtual void WriteText2Func()
{
Console.WriteLine("Text 2");
}
}
public class Special : Derived
{
public override void WriteText2Func()
{
//WriteText2Func will write nothing when
//method Foo is called from class Special.
//Also it can be modified to do something else.
}
}
回答by Julian Gold
My 2c for this is to implement the functionality you require to be called in a toolkit class and call that from wherever you need:
我的 2c 是实现您需要在工具包类中调用的功能,并从您需要的任何地方调用它:
// Util.cs
static class Util
{
static void DoSomething( FooBase foo ) {}
}
// FooBase.cs
class FooBase
{
virtual void Do() { Util.DoSomething( this ); }
}
// FooDerived.cs
class FooDerived : FooBase
{
override void Do() { ... }
}
// FooDerived2.cs
class FooDerived2 : FooDerived
{
override void Do() { Util.DoSomething( this ); }
}
This does require some thought as to access privilege, you may need to add some internal
accessor methods to facilitate the functionality.
这确实需要考虑访问权限,您可能需要添加一些internal
访问器方法来促进功能。