How to call base.base.method()?

// 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.

How can I rewrite SpecialDerived class so that middle class "Derived"'s method is not called?

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?

// 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.");
}
}
131319 次浏览

你不能从 C # 。在 IL 中,实际上支持这一点。您可以对任何父类执行非 virt 调用... ... 但请不要这样做。:)

答案(我知道这不是你想要的)是:

class SpecialDerived : Base
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}

事实上,您只能与从中继承的类进行直接交互。把这个类想象成一个层——根据它对派生类的需要,提供尽可能多或尽可能少的它或它的父类的功能。

编辑:

你的编辑工作,但我想我会使用这样的东西:

class Derived : Base
{
protected bool _useBaseSay = false;


public override void Say()
{
if(this._useBaseSay)
base.Say();
else
Console.WriteLine("Called from Derived");
}
}

当然,在实际的实现中,您可能为了扩展性和可维护性而做更多类似的事情:

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");
}
}

然后,派生类可以适当地控制其父类的状态。

这是一种糟糕的编程实践,在 C # 中是不允许的

  • 大基地的细节是基地的实现细节; 您不应该依赖它们。基类提供了一个超越了大基类的抽象; 您应该使用这个抽象,而不是构建一个旁路来避免它。

  • 为了举例说明前一点: 如果允许,这种模式将是另一种使代码易受脆弱基类故障影响的方法。假设 C派生自 BB派生自 AC中的代码使用 base.base调用 A的方法。然后,B的作者意识到他们在 B类中放了太多的齿轮,一个更好的方法是使中间类 B2A派生,而 BB2派生。改变之后,C中的代码调用的是 B2中的方法,而不是 A中的方法,因为 C的作者假设 B的实现细节,即它的直接基类是 A,永远不会改变。C # 中的许多设计决策都是为了减少各种脆弱的基本故障的可能性; 使 base.base非法的决策完全阻止了这种特殊的故障模式。

  • 您从您的基础中派生出来,因为您喜欢它的功能,并且希望重用和扩展它。如果你不喜欢它所做的事情,并且想要围绕它工作而不是与它一起工作,那么为什么你一开始就从中获得它呢?如果您希望使用和扩展这些功能,那么您可以自己从大基地中派生出来。

  • 出于安全性或语义一致性的目的,基础可能需要某些不变量,这些不变量由基础如何使用 Grandbase 方法的细节来维护。允许基类的派生类跳过维护这些不变量的代码可能会使基类处于不一致、损坏的状态。

您还可以在第一级派生类中创建一个简单的函数,以调用大基函数

如果您不能访问派生类源,但是需要除当前方法之外的所有派生类源,那么我建议您还应该执行派生类并调用派生类的实现。

这里有一个例子:

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

只是想在这里加上这一点,因为人们仍然回到这个问题,即使过了很多次。当然,这是不好的做法,但(原则上)仍然可以做作者想做的事情:

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

为什么不简单地将子类强制转换为特定的父类并调用特定的实现呢?这是一种特殊的情况,应该使用特殊的解决方案。但是,您必须在子方法中使用 new关键字。

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

从以前的文章中可以看出,如果需要规避类功能,那么类体系结构就有问题。这可能是对的,但是在一个大型成熟项目中,不能总是重构或重构类结构。不同级别的变更管理可能是一个问题,但是在重构之后保持现有功能运行相同并不总是一个琐碎的任务,特别是在时间限制的情况下。对于一个成熟的项目来说,在代码重组之后阻止各种回归测试通过是一项艰巨的任务; 经常会出现一些模糊的“怪异现象”。 在某些情况下,我们遇到了类似的问题: 继承的功能不应该执行(或者应该执行其他功能)。下面我们遵循的方法是将需要排除在外的基本代码放在一个单独的虚函数中。然后可以在派生类中重写此函数,并排除或更改其功能。在此示例中,可以防止“文本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.
}
}

我的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 ); }
}

这确实需要一些关于访问权限的思考,您可能需要添加一些 internal访问器方法来促进功能。

如果要访问基类数据,必须使用“ this”关键字或使用此关键字作为类的引用。

namespace thiskeyword
{
class Program
{
static void Main(string[] args)
{
I i = new I();
int res = i.m1();
Console.WriteLine(res);
Console.ReadLine();
}
}


public class E
{
new public int x = 3;
}


public class F:E
{
new public int x = 5;
}


public class G:F
{
new public int x = 50;
}


public class H:G
{
new public int x = 20;
}


public class I:H
{
new public int x = 30;


public int m1()
{
// (this as <classname >) will use for accessing data to base class


int z = (this as I).x + base.x + (this as G).x + (this as F).x + (this as E).x; // base.x refer to H
return z;
}
}
}

似乎有很多这样的问题围绕着继承祖父类的成员方法,在第二个类中重写它,然后再从祖父类调用它的方法。为什么不直接把祖父母的遗产传给孙子辈呢?

class A
{
private string mystring = "A";
public string Method1()
{
return mystring;
}
}


class B : A
{
// this inherits Method1() naturally
}


class C : B
{
// this inherits Method1() naturally
}




string newstring = "";
A a = new A();
B b = new B();
C c = new C();
newstring = a.Method1();// returns "A"
newstring = b.Method1();// returns "A"
newstring = c.Method1();// returns "A"

似乎很简单... ... 孙子在这里继承了爷爷奶奶的方法。想想看... ... 这就是“ Object”及其成员如 ToString ()如何被继承到 C # 中的所有类的。我认为微软在解释基本遗传问题上做得不够好。过于关注多态性和实现。当我深入研究他们的文档时,并没有这个非常基本的想法的例子。:(

我遇到了与 OP 相同的问题,在 OP 中,我只想重写中间 Class 中的一个方法,而不想重写所有其他方法。我的设想是:

类 A-基类,数据库访问,不可编辑。

类 B: A-“记录类型”特定功能(可编辑,但只有在向后兼容的情况下)。

类 C: B-一个特定客户端的一个特定字段。

我的做法与 OP 发布的第二部分非常相似,只不过我将基调用放入了它自己的方法中,我从 Say ()方法中调用了该方法。

class Derived : Base
{
public override void Say()
{
Console.WriteLine("Called from Derived.");


BaseSay();
}


protected virtual void BaseSay()
{
base.Say();
}
}


class SpecialDerived : Derived
{
    

public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.BaseSay();
}
}

您可以无止境地重复这个操作,例如,如果需要 ExtraSpecialDerived 重写 SpecialDerived,则给出 SpecialDerived 一个 BaseBaseSay ()方法。

这样做最好的一点是,如果派生程序将其继承从 Base 更改为 Base2,则所有其他重写都会跟进,而不需要进行更改。