Когда вы используете Event.GetInvocationList()
в классе Parent
, вы получаете доступ не к событию, а к автоматически сгенерированному полю делегата, имя которого совпадает с именем события. Это закрытый член, поэтому вы не можете получить к нему доступ из производного класса.
Однако, объявив событие явным добавлением / удалением методов доступа, вы можете решить эту проблему:
class Parent
{
protected EventHandler Handler { get; private set; }
public event EventHandler Event
{
add => Handler += value;
remove => Handler -= value;
}
}
class Child : Parent
{
private void SomeMethodInDerivedClass()
{
var handlers = Handler.GetInvocationList();
// ...
}
}
Обновление:
Если вы не можете изменить базовый класс, вы можете получить доступ к полю частного делегата с помощью отражения.
Примечание : Чтобы скопировать поле делегата, вам не нужно получать список вызовов, поскольку вы не можете назначить массив делегатов обработчику событий. Все делегаты C # получены из MulticastDelegate
, поэтому назначаемое значение уже будет содержать все подписки. Обратите также внимание, что даже многоадресные делегаты являются неизменяемыми, поэтому не бойтесь назначать исходный экземпляр делегата копии: когда вы добавляете новую подписку к исходному экземпляру, она не будет отражаться в копии (поэтому это работает в некоторой степени аналогично строки).
И решение:
public Child Copy()
{
Child copy = new Child()
{
Data = this.Data
};
FieldInfo eventBackingField = typeof(Parent).GetField(nameof(Event), BindingFlags.Instance | BindingFlags.NonPublic);
if (eventBackingField == null)
return; // oops, not an auto event, it has explicit accessors
// copy.Event = this.Event:
eventBackingField.SetValue(copy, eventBackingField.GetValue(this));
return copy;
}