Делегаты и наследование в c # - PullRequest
3 голосов
/ 08 августа 2011

У меня есть небольшая проблема с наследованием делегатов. Насколько я понимаю, делегат - это указатель на пару: экземпляр и метод, дело в том, что этот метод используется при создании делегата и не подвержен наследованию. Итак, это не сработает:

public class BaseObject {
  public delegate void del();

  public BaseObject() {
    next=Method;
  }

  public del next;
  public void ExecuteNext() {
    next();
  }

  public virtual void Method() {
    Debug.Log("BASE");
  }
}

public class InheritedObject:BaseObject {
  override public void Method() {
    Debug.Log("INHERITED");
  }
}
...

(new InheritedObject()).ExecuteNext();

Execute запускает базовый метод (), я хочу, чтобы он запускал унаследованный метод (). Я нашел способ обойти, но он неэффективен, отвлекает и очень подвержен ошибкам, в любом случае вот текущая рабочая версия, от которой я хотел бы избавиться:

class BaseObject {
  public delegate void del();

  BaseObject() {
    next=DoMethod;     /// using DoMethod here
  }

  public del next;
  public void ExecuteNext() {
    next();
  }


  public void DoMethod() {    /// using DoMethod here
    Method();
  }
  public virtual void Method() {
    // do base
  }
}

class InheritedObject:BaseObject {
  override public void Method() {
    // do inherited
  }
}

...

(new InheritedObject()).Execute();

Этот подход к DoMethod работает, но имеет много проблем,

  1. много бесполезного кода
  2. ошибка при использовании класса - легко ошибиться obj.next = DoMethod с obj.next = Method
  3. Ошибка при наследовании класса - я должен помнить, чтобы не наследовать DoMethod, а также множество виртуальных и переопределений.

Какие-нибудь предложения, как я могу сделать это лучше? Возможно, какая-то магия аннотаций, которая сама по себе делает DoMethod? Я уже думал о словарях - они здесь не очень хороши, они добавляют еще один уровень путаницы (Mono, .NET 2, Unity3d framework)

Ответы [ 3 ]

4 голосов
/ 08 августа 2011

В первом примере вы присваиваете делегату результат из Method();, поэтому, естественно, это означает, что метод Method (ahem) будет выполнен в этой точке назначить значение Игнорирование того факта, что Method равно void (что не будет компилироваться).

Во втором примере вы назначаете делегату ссылку на метод (который не обязательно должен быть методом экземпляра), что позволяет вам выполнить del на более позднем этапе.

У меня работает следующее:

class Program
{
    static void Main(string[] args)
    {
        var baseClass = new BaseObject();
        baseClass.Execute();

        var derivedClass = new DerivedObject();
        derivedClass.Execute();

        Console.ReadKey();
    }
}

class BaseObject
{
    public delegate void SomethingDelegate();
    public SomethingDelegate Delegate;

    public BaseObject()
    {
        Delegate += Something;
    }

    public virtual void Something()
    {
        Console.WriteLine("Base Class");
    }

    public void Execute()
    {
        Delegate();
    }
}

class DerivedObject : BaseObject
{
    public override void Something()
    {
        Console.WriteLine("Derived Class");
    }
}

В приведенном выше примере тот факт, что указатель делегата выражается как указатель на метод Something (из BaseObject), поскольку метод является виртуальным, вызов по-прежнему корректно отправляется переопределенному Something метод (из DerivedObject).

Разве вы не видите такое же поведение?

4 голосов
/ 08 августа 2011

Вы можете заменить next=DoMethod; на next= ()=>Method();, что по сути то же самое, но не требует от вас определения дополнительного метода для вашего класса.

3 голосов
/ 08 августа 2011

Нет, Execute запустит унаследованный метод.После внесения некоторого исправления в код я смог проверить его:

public class BaseObject {
  public delegate void del();

  public BaseObject() {
    next = Method;
  }

  public del next;
  public void Execute() {
    next();
  }

  public virtual void Method() {
    Console.WriteLine("base");
  }
}

public class InheritedObject : BaseObject {

  override public void Method() {
    Console.WriteLine("inherited");
  }

}

Вызывается:

(new InheritedObject()).Execute();

Вывод:

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