Есть ли способ указать область? - PullRequest
4 голосов
/ 22 февраля 2012

Рассмотрим этот пример кода:

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 ++ с оператором ::?

Ответы [ 4 ]

7 голосов
/ 22 февраля 2012

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

6 голосов
/ 22 февраля 2012

Ты слишком обдумываешь проблему.

  • Если вы хотите не виртуальную диспетчеризацию, тогда не делает методы виртуальными, во-первых, .

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

Например:

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 голос
/ 22 февраля 2012

Экземпляр Child будет вызывать собственную реализацию типа.

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

0 голосов
/ 22 февраля 2012

Ну, на самом деле это возможно как сказано здесь :

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...