Редактировать - Новый вопрос
Хорошо, давайте перефразируем вопрос более обобщенно.
Используя отражение, есть ли способ динамически вызывать во время выполнения метод базового класса, который вы можете переопределить. Вы не можете использовать ключевое слово base во время компиляции, потому что не можете быть уверены, что оно существует. Во время выполнения я хочу перечислить методы моих предков и вызвать методы предков.
Я пытался использовать GetMethods () и тому подобное, но все, что они возвращают, это «указатели» на наиболее производную реализацию метода. Не реализация в базовом классе.
Фон
Мы разрабатываем систему на C # 3.0 с относительно большой иерархией классов. Некоторые из этих классов в любой части иерархии имеют ресурсы, которые необходимо
утилизируются те, которые реализуют интерфейс IDisposable .
Проблема
Теперь, чтобы облегчить поддержку и рефакторинг кода, я хотел бы найти способ для классов, реализующих IDisposable,
для "автоматического" вызова base.Dispose (bDisposing) , если какие-либо предки также реализуют IDisposable. Таким образом, если какой-то класс выше в иерархии начинает реализовывать
или прекращает реализацию IDisposable, о котором позаботятся автоматически.
Вопрос в два раза.
- Во-первых, обнаружение, реализует ли какой-либо предок IDisposable.
- Во-вторых, вызывая базу. Уничтожить (bDisposing) условно.
В первой части, касающейся предков, реализующих IDisposable, мне удалось разобраться.
Вторая часть хитрая. Несмотря на все мои
усилия, я не смог вызвать base.Dispose (bDisposing) из производного класса. Все мои попытки провалились. Они либо вызвали
ошибки компиляции или вызванный неправильный метод Dispose (), который является наиболее производным, таким образом, цикл зацикливается навсегда.
Основная проблема в том, что вы не можете на самом деле ссылаться на base.Dispose () непосредственно в вашем коде, если нет такой вещи как
Предок, реализующий его ( Напоминаем, что, возможно, еще не было предков, еще реализующих IDisposable, но я хочу, чтобы производный код был готов, когда и если таковой будет
что-то случится в будущем ). Это оставляет нам механизмы Reflection , но я не нашел подходящего способа сделать это. Наш код довольно заполнен
продвинутые техники отражения, и я думаю, что не пропустил ничего очевидного.
Мое решение
Моим лучшим вариантом было использование условного кода в закомментированном коде. Изменение иерархии IDisposable приведет к поломке сборки
(если не существует IDisposable предка) или выведите исключение (если есть IDisposable предки, но base.Dispose не вызывается).
Вот код, который я публикую, чтобы показать вам, как выглядит мой метод Dispose (bDisposing). Я ставлю этот код в конце всех Dispose ()
методы по всей иерархии. Любые новые классы создаются из шаблонов, которые также включают этот код.
public class MyOtherClassBase
{
// ...
}
public class MyDerivedClass : MyOtherClassBase, ICalibrable
{
private bool m_bDisposed = false;
~MyDerivedClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool bDisposing)
{
if (!m_bDisposed) {
if (bDisposing) {
// Dispose managed resources
}
// Dispose unmanaged resources
}
m_bDisposed = true;
Type baseType = typeof(MyDerivedClass).BaseType;
if (baseType != null) {
if (baseType.GetInterface("IDisposable") != null) {
// If you have no ancestors implementing base.Dispose(...), comment
// the following line AND uncomment the throw.
//
// This way, if any of your ancestors decide one day to implement
// IDisposable you will know about it right away and proceed to
// uncomment the base.Dispose(...) in addition to commenting the throw.
//base.Dispose(bDisposing);
throw new ApplicationException("Ancestor base.Dispose(...) not called - "
+ baseType.ToString());
}
}
}
}
Итак, я спрашиваю, есть ли способ вызвать base.Dispose () вместо этого автоматически / условно?
Больше фона
В приложении есть еще один механизм, в котором все объекты зарегистрированы главным классом. Класс проверяет, реализуют ли они IDisposable.
Если это так, они утилизируются надлежащим образом приложением. Это позволяет избежать использования кода для использования классов
вызывая Dispose () вокруг себя. Таким образом, добавление IDisposable в класс, у которого нет предковой истории IDisposable, по-прежнему работает отлично.