Может ли базовый класс определить, переопределил ли производный класс виртуальный член? - PullRequest
6 голосов
/ 06 февраля 2009

Вот упрощенная версия моего класса:

public abstract class Task
{
    private static object LockObject = new object();

    protected virtual void UpdateSharedData() { }
    protected virtual void UpdateNonSharedData() { }

    public void Method()
    {
       lock(LockObject)
       {
          UpdateSharedData();
       }
       UpdateNonSharedData();
    }
}

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

Таким образом, (на первый взгляд) очевидная вещь, которую должен сделать метод, - это проверить и посмотреть, не перекрыла ли реализация UpdateSharedData текущего экземпляра реализацию базового класса. Я уверен, что это невозможно без использования отражения, и, вероятно, это нежелательно.

Я подумал о некоторых обходных путях к этому, но все они довольно неловко:

  • Добавьте защищенное свойство bool, которое устанавливает конструктор производного класса, и проверьте это свойство, чтобы увидеть, нужна ли блокировка. Это делает ужасную работу по сокрытию кода блокировки от производных классов.
  • Сделайте метод UpdateSharedData свойством делегата, установите любой производный класс свойство для закрытого метода в его конструкторе, и получить блокировку только в том случае, если делегат не равен NULL. Это лучше, но все равно отстой.

Ответы [ 3 ]

5 голосов
/ 06 февраля 2009

Что если вы определили абстрактную задачу и интерфейс IHasSharedData, то в методе вы проверяете, реализует ли производная задача IHasSharedData перед выполнением блокировки. Только классы, которые реализуют интерфейс, должны ждать. Я понимаю, что это не позволяет ответить на реальный вопрос, но я думаю, что это было бы более чистое решение, чем использование отражения. Надеюсь, вы найдете лучшее имя для интерфейса, которое будет более точно соответствовать тому, что на самом деле делают классы.

public interface IHasSharedData
{
    void UpdateSharedData();
}

public abstract class Task
{
    private static object LockObject = new object();

    protected virtual void UpdateNonSharedData() { }

    public void Method()
    {
         if (this is IHasSharedData)
         {
            lock(LockObject)
            {
                UpdateSharedData();
            }
         }
         UpdateNonSharedData();
    }
}

public class SharedDataTask : Task, IHasSharedData
{
    public void UpdateSharedData()
    {
       ...
    }
}
4 голосов
/ 06 февраля 2009

Вы можете сделать эту проверку с небольшим отражением:

bool IsUpdateSharedDataOverridden()
{
    Type t = this.GetType();
    MethodInfo m = subType.GetMethod("UpdateSharedData");

    return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task);
}
0 голосов
/ 06 февраля 2009

На самом деле, вы говорите о двух разных объектах:

public abstract class Task {    
    protected virtual void UpdateNonSharedData() { }

    public virtual void Method()    
    {   
        UpdateNonSharedData();    
    }
}

public abstract class TaskWithSharedData : Task {    
    private static object LockObject = new object();    

    protected virtual void UpdateSharedData() { }

    public overrides void Method()    
    {       
        lock(LockObject)
        {          
            UpdateSharedData();       
        }   
        base.Method();
    }
}

Но более идеальным решением будет шаблон стратегии.

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