С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.68/34: Рейтинг темы: голосов - 34, средняя оценка - 4.68
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614

Вызов события в производном классе, которое объявлено в базовом

13.10.2017, 20:53. Показов 6869. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток, Господа. Возник вопрос.
Есть класс A:
C#
1
2
3
4
5
public abstract class A
{
    public event EventHandler<EventArgs> SomeEvent = delegate { };
    public abstract void Foo();
}
И есть производный от него:
C#
1
2
3
4
5
6
7
public class B : A
{
    public void Foo()
    {
        SomeEvent( this, new EventArgs() );
    }
}
Так не будет работать. Вопрос: Почему? Ведь событие в базовом классе имеет уровень доступа public, разве я не могу его вызывать в классе наследнике?

Могу обойти это:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class A
{
    public abstract event EventHandler<EventArgs> SomeEvent;
    public abstract void Foo();
}
public class B : A
{
    public override event EventHandler<EventArgs> SomeEvent = delegate { };
    public void Foo()
    {
        SomeEvent( this, new EventArgs() );
    }
}
Так работает. Но в MSDN написано: Do not declare virtual events in a base class and override them in a derived class. The C# compiler does not handle these correctly and it is unpredictable whether a subscriber to the derived event will actually be subscribing to the base class event.

Вопросы:
1. Что делать?
2. Почему не работает?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.10.2017, 20:53
Ответы с готовыми решениями:

В базовом классе вводится символьный массив, а в производном - проверка на максимальную длину строки
Здравствуйте. Помогите найти ошибку при наследовании класса. Есть такая проблема - в базовом классе вводится символьный массив, а в...

Вызов оператора= в производном классе
#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;numeric&gt; using namespace std; template &lt;class T&gt; class Vector: public...

базовый и производный класс, в базовом объявлена переменная "protected", она недоступна по имени в производном классе! template <class T> воду мутит!
Друзья! Вот код #include &lt;stdio.h&gt; template &lt;class T&gt; class otets { protected: int peremennaya; }; template...

8
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18245 / 14163 / 5366
Регистрация: 17.03.2014
Сообщений: 28,848
Записей в блоге: 1
13.10.2017, 21:29
Bretbas, событие принадлежит классу в котором объявлено и только он имеет право его генерировать. Исправить можно по разному:
- переписать код так чтобы наследникам не было необходимости генерировать событие родителя
- сделать protected метод в базовом классе генерирующий событие
- заменить событие на делегат
- использовать { add { } remove { } } блок для события, хранить подписчиков в protected поле родительского класса
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
14.10.2017, 07:58  [ТС]
OwenGlendower, Подскажите пожалуйста, у меня есть базовый класс, который в себе имеет 3 события - ExecuteStart, ExecuteStep, ExecuteCompleted. Также этот базовый класс имеет метод Execute(), который нужно будет переопределить в наследниках. И последнее, что имеет базовый класс, это метод Start(), который генерирует вначале событие ExecuteStart, потом выполняет Execute(), и затем генерирует событие ExecuteCompleted. Так вот мне нужно сделать так, чтобы событие ExecuteStep генерировалось внутри Execute(), а это значит, что мне нужно его генерировать в наследнике.
У меня получилось реализовать это таким образом, как я уже показывал выше:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class Base
{
    public event EventHandler<EventArgs> ExecuteStart = delegate {};
    public abstract event EventHandler<EventArgs> ExecuteStep;
    public event EventHandler<EventArgs> ExecuteCompleted = delegate {};
    public abstract void Execute();
    public void Start()
    {
        ExecuteStart( this, new EventArgs() );
        Execute();
        ExecuteCompleted( this, new EventArgs() );
    }
}
class Derrived : Base
{
    public override event EventHandler<EventArgs> ExecuteStep = delegate {};
    
    public override void Execute()
    {
        ...
        EventHandler( this, new EventArgs() );
        ...
    }
Цитата Сообщение от OwenGlendower Посмотреть сообщение
- переписать код так чтобы наследникам не было необходимости генерировать событие родителя
- сделать protected метод в базовом классе генерирующий событие
- заменить событие на делегат
- использовать { add { } remove { } } блок для события, хранить подписчиков в protected поле родительского класса
В Ваших способах, не указано сделать так, как сделал я. Вы можете объяснить, почему нельзя так делать, как сделал я?
Просто, на мой взгляд, это выглядит симпатичнее. Но меня насторожила выписка из MSDN
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18245 / 14163 / 5366
Регистрация: 17.03.2014
Сообщений: 28,848
Записей в блоге: 1
16.10.2017, 00:09
Bretbas, в MSDN же ясно сказано. Виртуальные события не работают так как ожидается. Вот простой пример
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Main()
{
    B b = new B();
    b.Test += () => Console.WriteLine("1");
    b.Raise();
}
 
class A
{
    public virtual event Action Test;
    
    public void Raise()
    {
        if (Test != null) Test();
    }
}
 
class B : A
{
    public override event Action Test;
}
Вызов Raise по идее должен генерировать событие B.Test, но это не происходит. Поэтому лучше избегать виртуальных событий.
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
16.10.2017, 08:10  [ТС]
OwenGlendower, Ну я не говорю про виртуальные события, говорю про абстрактные. Хотя и те и те должны быть в виртуальной таблице, по идее.
Так вот, если мы сделаем абстрактное событие в классе A, то мы его не сможем сгенерировать в классе A, а именно в методе Raise(). Но мне это и не надо. Мне нужно его генерировать в классе наследнике от A
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
16.10.2017, 10:12
Цитата Сообщение от Bretbas Посмотреть сообщение
Мне нужно его генерировать в классе наследнике от A
Предоставьте в классе А защищенный метод, генерирующий событие:
C#
1
2
3
4
5
6
7
8
9
10
public abstract class A
{
    public event EventHandler<EventArgs> SomeEvent = delegate { };
    public abstract void Foo();
 
    protected void RaiseSomeEvent(EventArgs e)
    {
        SomeEvent?.Invoke(this, e);
    }
}
C#
1
2
3
4
5
6
7
public class B : A
{
    public void Foo()
    {
        RaiseSomeEvent(EventArgs.Empty);
    }
}
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
16.10.2017, 17:18  [ТС]
kolorotur, Базара нет, этот способ я еще на MSDN я увидел Но я все же хочу узнать, что будет, если переопределять абстрактные события классах наследниках и генерировать их там же? Просто у меня ошибки никакой при этом пока что не возникало. Поэтому мне просто интересно, почему так не следует делать. Или все таки так можно делать, но предупреждение было только о виртуальный событиях.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
16.10.2017, 20:28
Лучший ответ Сообщение было отмечено Bretbas как решение

Решение

Цитата Сообщение от Bretbas Посмотреть сообщение
что будет, если переопределять абстрактные события классах наследниках и генерировать их там же?
Будет неразбериха, как примером показал выше товарищ OwenGlendower.

Цитата Сообщение от Bretbas Посмотреть сообщение
почему так не следует делать.
Потому что обработчик будет то вызываться, то не вызываться — в зависимости от того, как была произведена подписка на событие и как оно было сгенерировано.

Цитата Сообщение от Bretbas Посмотреть сообщение
Или все таки так можно делать
Ну если не возникает ошибки компиляции, то конечно можно
Другое дело, что опасно.
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
16.10.2017, 21:13  [ТС]
kolorotur, OwenGlendower, Спасибо. Все ясно
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.10.2017, 21:13
Помогаю со студенческими работами здесь

В производном классе вызов приватного метода базового класса
Добрый вечер. Помогите понять одну вещь. Имеется такое наследование: class test1 { public: void pubF() { ...

Вызов метода базового класса игнорируя переопределенный метод в производном классе
Как вызвать метод базового класса игнорируя переопределенный метод в производном классе. PS переопределение метода в производном классе...

Есть базовый и производный класс, в базовом определена функция, необходимо её объявить в производном!
Как-то так, что ли: class x { public: void f_0 (){}; }; class y: public x { public: //Тут у меня пойдёт...

Event вызов события в классе
Всем привет. Не судите строго, только учусь. 1. Есть класс который работает с TCP 2. В классе обрабатывается получение данных. Так...

Один и тот же метод объявлен в базовом private, а в производном public; и по ссылке на производный класс он не вызывается!
Прежде всего, вот код который компилится и работает, он описан у Эккеля (глава 8 &quot;Полиморфизм&quot;): import static...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru