Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.03.2016, 18:54   #1
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
Печаль События. "Короткая" и "длинная" запись.

Уважаемые форумчане. Заранее прошу прощения за копи-паст из одной ветки форума в другой, просто решил, что здесь этому вопросу вернее лежать.

Пытаюсь разобраться в событиях. Возник следующий вопрос.

Как я понял есть короткая (сокращенная) запись определения события. Выглядит она вот так:
Код:
public event EventHandler<CarInfoEventArgs> NewCarInfo;
В приведенном выше строчке класс CarInfoEventArgs наследуется от EventArgs. Это пример из книги.
В ней же пишется, что длинная форма сокращенной нотации выглядит следующим образом:
Код:
private delegate EventHandler<CarInfoEventArgs> newCarInfo;
public event EventHandler<CarInfoEventArgs> NewCarInfo
{
	add
	{
		newCarInfo+=value;
	}
	remove
	{
		newCarInfo-=value;
	}
}
Ну коль учебник утверждает, что это эквивалентная запись, то думаю заменю сокращенную нотацию на полную, за одно добавлю вывод на консоль сообщения о том, что добавился новый подписчик. Но не тут-то было. Приведу полный листинг рабочего кода.
Код:
using System;

public class Test
{
	public static void Main()
	{
		var oleg = new CarDealer("Oleg");
		var vasya = new CarDealer("Vasya");
		var misha = new Consumer("Misha");
		oleg.NewCarInfo+=misha.NewCarIsHere;
		oleg.NewCar("Ferrari");
		vasya.NewCar("ZAZ");
		vasya.NewCarInfo+=misha.NewCarIsHere;
		var maks = new Consumer("Max");
		vasya.NewCarInfo+=maks.NewCarIsHere;
		oleg.NewCar("Opel");
		vasya.NewCar("VAZ");
		vasya.NewCar("UAZ");
		oleg.NewCar("Renault");
		oleg.NewCarInfo+=maks.NewCarIsHere;
		oleg.NewCar("Peugeot");
		vasya.NewCarInfo-=maks.NewCarIsHere;
		oleg.NewCar("Mazda");
		oleg.NewCarInfo-=misha.NewCarIsHere;
		vasya.NewCar("GAZ");
	}
}

public class CarInfoEventArgs: EventArgs
{
	public CarInfoEventArgs(string car)
	{
		this.Car=car;
	}
	public string Car {get; private set;}
}

public class CarDealer
{
	public event EventHandler<CarInfoEventArgs> NewCarInfo;
	public string dealer {get; private set;}
	public CarDealer (string dealer)
	{
		this.dealer=dealer;
		Console.WriteLine("New car dealer - {0}", dealer);
	}
	public void NewCar(string car)
	{
		Console.WriteLine("{0}, new car {1}", dealer, car);
		RaiseNewCarInfo(car);
	}
	protected virtual void RaiseNewCarInfo(string car)
	{
		EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo;
		if (newCarInfo !=null)
		{
			newCarInfo(this, new CarInfoEventArgs(car));
		}
	}
}

public class Consumer
{
	private string name;
	public Consumer(string name)
	{
		this.name=name;
		Console.WriteLine("New car consumer - {0}", name);
	}
	
	public void NewCarIsHere(object sender, CarInfoEventArgs e)
	{
		Console.WriteLine("{0}: car {1} is new", name, e.Car);
	}
}
Такой код выполняется. Но если я заменю строку
Код:
public event EventHandler<CarInfoEventArgs> NewCarInfo;
на
Код:
private delegate EventHandler<CarInfoEventArgs> newCarInfo;
public event EventHandler<CarInfoEventArgs> NewCarInfo
{
	add
	{
		newCarInfo+=value;
	}
	remove
	{
		newCarInfo-=value;
	}
}
Компилятор выдает ошибку, что не хватает открывающейся круглой скобки в строке с объявлением приватного делегата. Ну думаю, не хватает в объявлении делегата параметров, дай допишу. Привел строку эту к такому виду:
Код:
private delegate EventHandler<CarInfoEventArgs> newCarInfo (object sender, CarInfoEventArgs e);
После этого он стал выдавать ошибку, что внутри блоков add и remove переменная CarDealer.newCarInfo является "тип", который недопустим в данном контексте.
Думаю, ладно. Пойду по пути наименьшего сопротивления. Просто удалю эту строчку, авось компилятор сам за меня создаст этот делегат, тем более на хабре нашел какую-то статью, в которой длинная запись события используется именно без объявления приватного делегата. Значит меняю код события на следующий:
Код:
public event EventHandler<CarInfoEventArgs> NewCarInfo
{
	add
	{
		NewCarInfo+=value;
	}
	remove
	{
		NewCarInfo-=value;
	}
}
Опять ошибка, но на этот раз уже компилятор ссылается на строчку в методе RaiseNewCarInfo(), а именно на эту:
Код:
EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo;
И говорит, что, мол, событие CarDealer.NewCarInfo может находиться только в левой части операции += или -=.

Люди добрые, помогите разобраться, как в данном случае использовать полную запись события?
max_prorok вне форума Ответить с цитированием
Старый 16.03.2016, 19:58   #2
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Учебник врет, event и делегат - совсем не эквивалентные вещи, хотя и похожие по свойствам.
Event - это "обертка" для делегата, которая позволяет только подписаться на событие, или отписаться от него, но не позволяет получить ссылку на сам объект делегата, тем самым обеспечивая инкапсуляцию.

В вашем случае я бы оставил "полную" запись (с event-ом и приватным делегатом), а invoke делал бы именно делегату. (EventHandler<CarInfoEventArgs> newCarInfo =this.NewCarInfo).

Публичные делегаты - вещь весьма опасная, да и корявая по своей сути. Для этого event'ы и придумали
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Старый 16.03.2016, 20:14   #3
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

стоп стоп стоп. ключевое слово delegate служит для объявления типа делегата.

эквивалент короткой записи события это:
Код:
private EventHandler<CarInfoEventArgs> newCarInfo;
public event EventHandler<CarInfoEventArgs> NewCarInfo
{
	add
	{
		newCarInfo+=value;
	}
	remove
	{
		newCarInfo-=value;
	}
}
правда не помню как там с иницилизацией.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 16.03.2016, 20:27   #4
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Цитата:
стоп стоп стоп. ключевое слово delegate служит для объявления типа делегата.
Все верно. EventHandler<CarInfoEventArgs> - это generic делегат, тип которого объявлен в mscorlib.dll (public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e), или что-то вроде того)
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Старый 16.03.2016, 20:38   #5
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
По умолчанию

Фух. Спсибо большое за помощь. А то я чуть голову не сломал, где загвоздка. Ох уж эти книги... Нельзя им доверять. На одну главу как минимум уже вторая опечатка. Точнее в первый раз были издержки перевода касаемо группового делегата. Когда через foreach он добавлял лямбда-выражения. А в книге было написано, что он суммировал их о_О.
max_prorok вне форума Ответить с цитированием
Старый 16.03.2016, 20:42   #6
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
По умолчанию

Да-да. Я уже тоже посмотрел и сообразил, что я пытался таким образом объявить свой собственный делегат, который имеет имя такое же как уже у существующего (созданного создателями C#) делегата. Еще раз всем спасибо за помощь.
На очереди разбор вопроса касаемо слабый событий и WeakEventManager. Больно запутанная история там получается.
max_prorok вне форума Ответить с цитированием
Старый 17.03.2016, 10:50   #7
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
По умолчанию

С событием, построенным на базовом делегате EventHandler<T> я вроде разобрался. Но что-то пока не могу разобраться вот с какой штукой.
Используя полную версию определения события хочу вставить туда вот такую строчку, которая выводила бы, что на события такого-то экземпляра подписался такой-то прослушиватель. Чтобы это выглядело как-то так:
Код:
public event EventHandler<CarInfoEventArgs> NewCarInfo
{
	add
	{
		newCarInfo+=value;
		Console.WriteLine("{0} have a new listener - {1}", dealer, name);
	}
	remove
	{
		newCarInfo-=value;
		Console.WriteLine("{0} lost a listener - {1}", dealer, name);
	}
}
И тут у меня возник вопрос. А реально ли как-нибудь передать значение переменной name экземпляра класса, метод которого мы подписываем или отписываем от события?
max_prorok вне форума Ответить с цитированием
Старый 17.03.2016, 11:59   #8
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Имя метода-обработчика события - value.Method.Name
Имя класса, в котором обработчик события - value.Method.DeclaringType.Name
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Старый 17.03.2016, 12:27   #9
max_prorok
Форумчанин
 
Регистрация: 06.10.2011
Сообщений: 181
По умолчанию

Цитата:
Сообщение от Luuzuk Посмотреть сообщение
Имя метода-обработчика события - value.Method.Name
Имя класса, в котором обработчик события - value.Method.DeclaringType.Name
Спасибо за информацию, но это немного не то, что я хотел.
Есть класс-издатель - CarDealer. Есть класс-прослушиватель Consumer. В классе Consumer есть стринговая переменная name. Так вот реально ли в определение события (в блок add и remove вставить код, использующий значение этой переменной)
Например, создан экземпляр класса-прослушивателя vasya, в котором name="Vasya". Так же создан экземпляр класса-издателя misha, в котором dealer="Misha". Необходимо, чтобы при подписке vasya на misha выводилась на консоль следующая строчка:
Misha have a new listener - Vasya.
Реально ли это как-нибудь получить?
max_prorok вне форума Ответить с цитированием
Старый 17.03.2016, 13:35   #10
Luuzuk
Форумчанин
 
Аватар для Luuzuk
 
Регистрация: 18.01.2012
Сообщений: 975
По умолчанию

Не думаю
Благодарить в репутацию. Проклинать — туда же
Luuzuk вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
C# События. "Короткая" и "длинная" записи. max_prorok Помощь студентам 0 16.03.2016 16:57