代码之家  ›  专栏  ›  技术社区  ›  AZ.

如何呼叫基地。基础方法()?

  •  98
  • AZ.  · 技术社区  · 16 年前
    // 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();
        }
    }
    

    结果是:

    从特殊来源调用。
    从派生调用。/*这是意料之中的*/
    从基地打来的。

    如何重写SpecialDrived类,以便不调用中产阶级“派生”的方法?

    更新: 我希望从派生类而不是基类继承的原因是派生类包含许多其他实现。既然我做不到 base.base.method() 在这里,我想最好的方法是做以下事情?

    //无法更改源代码

    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.");
        }
    }
    
    12 回复  |  直到 8 年前
        1
  •  122
  •   Evk    11 年前

    我只想在这里补充一点,因为人们在很多次之后仍然会回到这个问题上来。当然,这是一种不好的做法,但仍然有可能(原则上)做作者想做的事情:

    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();            
        }
    }
    
        2
  •  101
  •   Eric Lippert    6 年前

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

    • grandbase的细节是该基地的实施细节;你不应该依赖他们。基类提供了对grandbase的抽象;你应该使用这种抽象,而不是建立一个旁路来避免它。

    • 为了说明前一点的一个具体例子:如果允许的话,这种模式将是另一种使代码易受脆弱基类故障影响的方式。认为 C 源于 B 这源于 A .输入代码 C 使用 base.base 调用 A. .然后是 B 意识到他们在课堂上放了太多装备 B ,一个更好的方法是让中产阶级 B2 这源于 A. 和 B 源于 地下二层 .更改后,输入代码 C 正在调用中的方法 地下二层 ,不在 A. 因为 C 的作者假设 B ,即它的直接基类是 A. ,永远不会改变。C#中的许多设计决策都是为了降低各种脆性基底失效的可能性;做出的决定 基础基础 非法完全阻止了这种失败模式的特殊味道。

    • 你从你的基础中衍生出来,因为你喜欢它的功能,并且想要重用和扩展它。如果你不喜欢它所做的,并且想围绕它工作,而不是与它一起工作,那么你首先为什么要从中获得灵感?如果你想使用和扩展grandbase的功能,那就自己开发吧。

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

        3
  •  22
  •   rh.    16 年前

    你不能从C#开始。从IL来看,这实际上是受支持的。您可以对任何父类执行非virt调用。。。但请不要。:)

        4
  •  10
  •   JoshJordan    16 年前

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

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

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

        5
  •  7
  •   Pavel    10 年前
    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(); 
        }
    }
    
        6
  •  7
  •   Massimiliano Kraus The Angry Programmer    9 年前

    为什么不简单地将子类强制转换为特定的父类,然后调用特定的实现呢?这是一种特殊情况,应使用特殊情况解决方案。你必须使用 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());
        }
    }
    
        7
  •  4
  •   Rajesh    15 年前

    您还可以在一级派生类中生成一个简单的函数,以调用grand base函数

        8
  •  3
  •   Julian Gold    10 年前

    我的目标是实现在toolkit类中需要调用的功能,并在任何需要的地方调用它:

    // 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 访问器方法来促进功能。

        9
  •  1
  •   yoel halb    13 年前

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

    下面是一个例子:

    //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();  
         }         
    }
    
        10
  •  0
  •   Massimiliano Kraus The Angry Programmer    9 年前

    从之前的文章中可以看出,如果需要规避类功能,那么类架构中就有问题。这可能是真的,但在一个大型成熟项目中,不能总是重构或重构类结构。不同级别的变更管理可能是一个问题,但在重构后保持现有功能运行不变并不总是一项简单的任务,尤其是在时间限制适用的情况下。在一个成熟的项目中,在代码重组后,防止各种回归测试通过是一项相当艰巨的任务;经常会出现一些晦涩难懂的“怪事”。 在某些情况下,我们遇到了类似的问题,继承的功能不应该执行(或者应该执行其他操作)。下面我们采用的方法是将需要排除的基本代码放在一个单独的虚拟函数中。然后可以在派生类中重写该函数,并排除或更改该功能。在本例中,可以防止“文本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.
        }
    }
    
        11
  •  0
  •   Stokely    7 年前

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

    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"
    

    似乎很简单。。。。孙辈在这里继承了祖父母的方法。想想看。。。。。这就是C#中“Object”及其成员ToString()被继承到所有类的方式。我认为微软在解释基本继承方面做得不好。对多态性和实现的关注太多了。当我翻阅他们的文档时,没有任何关于这个非常基本的想法的例子(

        12
  •  -3
  •   krlzlx    9 年前

    如果您想访问基类数据,您必须使用“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;
            }
        }
    }