2012-02-22 4 views
4

Рассмотрим этот пример кода:Есть ли способ указать область?

public abstract class Parent 
{ 
    public int val; 
    public Parent() 
    { 
     val = 0; 
    } 
    public virtual void foo() 
    { 
     inc(); 
    } 

    public virtual void inc() 
    { 
     val = val + 10; 
    } 
} 

public class Child : Parent 
{ 
    public override void foo() 
    { 
     base.foo(); 
    } 

    public override void inc() 
    { 
     val++; 
    } 
} 

static void Main(string[] args) 
{ 
    Parent p = new Child(); 
    Console.WriteLine("p.val = " + p.val); //Output: p.val = 0 
    p.foo(); 
    Console.WriteLine("P.val = " + p.val); //Output: p.val = 1 
} 

Я предполагаю, inc() класса Parent не дозвонились, потому что {this} указатель на самом деле указывает на объект ребенка так версия у ребенка inc() будет вызываться из родительского объекта функция foo(). Есть ли способ заставить функцию родителя foo() всегда вызывать функцию родителя inc() Как вы могли в C++ с оператором ::?

+1

Что делать, если Parent.inc() не объявлен как «виртуальный»? – niaher

+1

Разве это не побеждает весь смысл наличия полиморфного foo()? Даже если вы сделали Parent :: foo() {this.inc()}, он все равно вызовет Child :: foo – StuartLC

+1

. Я уверен, что вы можете сделать это с отражением.И, конечно, ключевое слово 'base', которое не поддерживает все поддерживаемые C++' :: '. – CodesInChaos

ответ

6

Вы передумали проблему.

  • Если вы хотите невиртуальной отправку того не делает методы виртуальными в первую очередь.

  • Если вы хотите, как виртуальные, так и невиртуальный отправка затем сделать два метода, один виртуальный и один статический

Например:

class Base 
{ 
    protected static void NonVirtualFoo(Base b) 
    { 
     // Whatever 
    } 
    public virtual void Foo() 
    { 
     Base.NonVirtualFoo(this); 
    } 
} 

class Derived : Base 
{ 
    protected new static void NonVirtualFoo(Derived d) 
    { 
     // Whatever 
    } 
    public override void Foo() 
    { 
     Derived.NonVirtualFoo(this); 
     Base.NonVirtualFoo(this); 
    } 
} 

использовать правильный инструмент для работа. Если вы хотите виртуальную отправку, то вызовите виртуальный метод. Если вам нужна статическая отправка, то вызовите статический метод. Не пытайтесь взять молот на виртуальный метод и сделать его статически отправленным; это работает против всей цели инструмента.

1

Экземпляр Child вызовет реализацию своего типа.

foo() называет base.foo() и base.foo()inc() вызовов, которые в данном случае inc() от ребенка, так как экземпляр типа для детей, и будет использовать эту реализацию.

7

Нет, единственный способ виртуального метода, который можно назвать виртуальным, - это не base.Foo. Конечно, вы могли бы написать не виртуальный метод в Parent и сделать так, чтобы он вызывал Parent.foo(), а также реализацию по умолчанию Parent.inc().

0

Ну, это на самом деле можно as said here:

Это делает трюк:

public abstract class Parent 
{ 
    public int val; 

    public Parent() 
    { 
     val = 0; 
    } 

    public virtual void foo() 
    { 
     MethodInfo method = typeof(Parent).GetMethod("inc"); 
     DynamicMethod dm = new DynamicMethod("BaseInc", null, new Type[] { typeof(Parent) }, typeof(Parent)); 
     ILGenerator gen = dm.GetILGenerator(); 
     gen.Emit(OpCodes.Ldarg_1); 
     gen.Emit(OpCodes.Call, method); 
     gen.Emit(OpCodes.Ret); 

     var BaseInc = (Action<Parent>)dm.CreateDelegate(typeof(Action<Parent>)); 
     BaseInc(this); 
    } 

    public virtual void inc() 
    { 
     val = val + 10; 
    } 
} 

Но это только доказательство концепции: это ужасно и полностью ломает полиморфизм.

Я не думаю, что у вас есть веская причина, чтобы написать это.

+0

Действительно ли необходимо использовать codegen, а не просто использовать нормальное отражение с помощью метода method.Invoke (this, null) '? – svick

+0

@svick Да. 'method.Invoke (this, null)' будет вызывать метод override 'inc'. – ken2k

Смежные вопросы