pass parameter new inherit define c# polymorphism

c# - parameter - ¿Cómo llamar a base.base.method()?



define a constructor c# (11)

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

El resultado es:

Llamado de Special Derived.
Llamado de Derived. / * esto no se espera * /
Llamado desde la Base.

¿Cómo puedo volver a escribir la clase SpecialDerived para que no se llame al método "Derived" de clase media?

ACTUALIZACIÓN: La razón por la que deseo heredar de Derived en lugar de Base es que la clase Derived contiene muchas otras implementaciones. Como no puedo hacer base.base.method() aquí, ¿supongo que la mejor manera es hacer lo siguiente?

// No se puede cambiar el código fuente

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


¿Por qué no simplemente lanzar la clase hija a una clase primaria específica e invocar la implementación específica entonces? Esta es una situación de caso especial y se debe usar una solución de caso especial. Sin embargo, deberá usar la new palabra clave en los métodos secundarios.

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


Como se puede ver en publicaciones anteriores, se puede argumentar que si la funcionalidad de la clase necesita ser eludida, entonces algo está mal en la arquitectura de la clase. Eso podría ser cierto, pero no siempre se puede reestructurar o refactorizar la estructura de clases en un gran proyecto maduro. Los distintos niveles de administración de cambios pueden ser un problema, pero mantener la funcionalidad existente operando de la misma forma después de la refactorización no siempre es una tarea trivial, especialmente si se aplican restricciones de tiempo. En un proyecto maduro puede ser una gran tarea evitar que pasen varias pruebas de regresión después de una reestructuración del código; a menudo hay "rarezas" oscuras que aparecen. Tuvimos un problema similar en algunos casos. La funcionalidad heredada no debería ejecutarse (o debería realizar otra cosa). El enfoque que seguimos a continuación, fue poner el código base que necesita ser excluido en una función virtual separada. Esta función puede ser anulada en la clase derivada y la funcionalidad excluida o alterada. En este ejemplo, se puede evitar que "Texto 2" salga en la clase derivada.

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


En los casos en que no tenga acceso al origen de clase derivado, pero necesite todo el origen de la clase derivada además del método actual, le recomendaría que también haga una clase derivada y llame a la implementación de la clase derivada.

Aquí hay un ejemplo:

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


Esta es una mala práctica de programación, y no está permitida en C #. Es una mala práctica de programación porque

  • Los detalles de la grandbase son detalles de implementación de la base; no deberías confiar en ellos. La clase base proporciona una abstracción general de la grandbase; deberías estar usando esa abstracción, no construir un bypass para evitarla.

  • Se deriva de su base porque le gusta lo que hace y desea reutilizar y ampliar. Si no le gusta lo que hace y quiere evitarlo, en lugar de trabajar con él, ¿por qué se deriva de él en primer lugar? Derive del grandbase usted mismo si esa es la funcionalidad que desea usar y extender.

  • La base puede requerir ciertas invariantes para propósitos de seguridad o consistencia semántica mantenidas por los detalles de cómo la base usa los métodos de la grandbase. Permitir que una clase derivada de la base omita el código que mantiene esas invariantes podría poner la base en un estado incoherente y corrupto.


La respuesta (que sé que no es lo que estás buscando) es:

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

La verdad es que solo tienes interacción directa con la clase de la que heredas. Piense en esa clase como una capa, proporcionando tanto o tan poco de ella o la funcionalidad de sus padres como desee a sus clases derivadas.

EDITAR:

Tu edición funciona, pero creo que usaría algo como esto:

class Derived : Base { protected bool _useBaseSay = false; public override void Say() { if(this._useBaseSay) base.Say(); else Console.WriteLine("Called from Derived"); } }

Por supuesto, en una implementación real, puede hacer algo como esto para la extensibilidad y el mantenimiento:

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

Entonces, las clases derivadas pueden controlar el estado de sus padres de manera apropiada.


Mi 2c para esto es implementar la funcionalidad que necesita para ser llamado en una clase de kit de herramientas y llamarlo desde donde lo necesite:

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

Esto requiere una reflexión sobre el privilegio de acceso, puede que necesite agregar algunos métodos de acceso internal para facilitar la funcionalidad.


No puedes desde C #. Desde IL, esto es realmente compatible. Puede hacer una llamada no virtua a cualquiera de sus clases de padres ... pero no lo haga. :)


Si desea acceder a los datos de la clase base, debe utilizar la palabra clave "this" o utilizar esta palabra clave como referencia para la clase.

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


Solo quiero agregar esto aquí, ya que las personas aún vuelven a esta pregunta incluso después de mucho tiempo. Por supuesto, es una mala práctica, pero aún es posible (en principio) hacer lo que el autor quiere con:

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


También puede hacer una función simple en la clase derivada de primer nivel, para llamar a la función gran base


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