Pull to refresh

Comments 91

Всё как бы знаешь и понимаешь, а как спросят — не можешь подобрать слов. Спасибо за обзор.
Отлично. Спасибо за четкое разьяснение.
Чем event отличается от delegate? Права урезает, чтоб не хулиганили :)
Рихтер говорит, что компилятор для event кроме делегата генерирует еще два открытых метода. так что разница есть
Это аспект, реализующий отличие номер 2) про ограничение возможностей доступа к делегату. Danov прав.
Касательно вопроса 2 (по всей программе) — а если эвентов в интерфейсах не было, но зато были кое-где реализованы add/remove? Таки отвалится
что есть не чем иным как синтаксическим сахаром
Да ну, ничего не изменится?
у вас public event
и как вы думаете, что скажет компилятор если дальше по коду будет:
A a = new A();
a.DoWork += AfterSomeWork;
?
Так что разница есть.

PS (не к вам, просто вспомнил)
пришёл как то на собеседование(по .net) парниша, собеседовал его в основном ПМ, я так «послушать был», диалог примерно такой:
-какие способы/объекты синхронизации вы знаете?
-lock! (гордо так)
-а ещё?
-а я только его использовал…


Мораль — больше читайте.
>a.DoWork += AfterSomeWork;
>и как вы думаете, что скажет компилятор

А что мне думать? :) Я знаю. Компилятор ничего не скажет. Вставьте в студию и проверьте. Спасибо за совет — читаю регулярно.
Честно, реально бесят такие вопросы «А что будет, если я вот тут кое-что подправлю». Так и хочется ответить «Б? я, чё за х#й@я, да п$зд*ц будет конечно же».
Просто иногда человека нужно оценивать не за сами знания, а за способность эти знания усваивать. А то, что он из тако-то книжки не смог наизусть запомнить n-ую строку i-ого абзаца, это ещё ни о чём не говорит.
Вы не правы. Это же «арифметика» :)
Вот нас в универе как ....: брали схему, а что будет если вот тут перемкнуть? а что если тут оборвать?
Это очень способствует развитию конструктивного мышления. Работодателю нужны навыки. Он и проверяет их. Причем в данном примере на очень базовых для программера вещах.
Да? А если вам на собеседовании дадут схему, и спросят, что изменится, если молотком ударить прямо по её центру, как вы будете отвечать?
Конструктивное мышление, это не заменять одно на другое и думать «И что же в программе перестанет работать?»…
Это как раз оно самое… особенно когда делаешь много рефакторинга, то вопрос «И что же в программе перестанет работать?» будоражит голову больше всего :)
Рефакторинг — эт всё же немножко другое. При рефакторинге вы можете изменить код методов с целью оптимизации, изменить интерфейсы, которые находятся на стадии разработки.
Но когда вы написали готовый модуль, и он используется в нескольких программах, вы же не будете его менять и ждать, что что-то сломается, это же глупо.
Написанные до этого автоматические тесты подскажут.
Любую хорошую идею можно довести до абсурда
А насчет «способности усваивать знаний» расскажу такую байку. Приходит ко мне студент (это больше к студенткам относится :) на экзамен и начинает, глядя на потолок, рассказывать конспект лекции. Хорошо усвоил знания? Отлично!
Но стоит лишь прервать и спросить по делу: А почему именно так? А зачем? И чел уходит с тройкой или на второй круг. Бывало, что «отлично» получали студенты, которые и конспекта не видели. А потому, что смогли ответить на вопросы «почему»и «зачем».
На самом деле это не базовые знания, а частности. Базовые знания это спросить чего такое хеш, например и зачем оно надо.
А вот когда начинают спрашивать всякую лабуду типа почему ++i лучше i++ и что будет, если я вот тут подправлю то хочется послать просто такого загадочника.
Хотя в любом случае спасибо за напоминание, что event это тот же делегат + пара методов.
Вот, и я про то же.
Ну если сфера embedded и вы занимаетесь написанием библиотек для компилятора микс С и Асма то этот вопрос первого уровня :)
В том-то и дело, можно досконально изучить платформу .net, знать например о том, какие модификаторы доступа есть в .net, но отсутствуют в C#, но на практике не написать ничего полезного. Именно поэтому я и говорю, что сырые знания не являются показателем.
> сырые знания не являются показателем
Я с Вами солидарен! Не знания покупает работодатель, а навыки. Смотрят на опыт. А идиотские вопросы задают, чтобы проверить алгоритмическое или нестандартное мышление, например.
Что лучше ++i или i++ я и сам не знаю. Это надо из контекста смотреть. Вполне возможно, что этот вопрос открытый. Не важно, что будет отвечать кандидат, а важно как он это будет делать. Например, я разбирался с архитектурой CPU и рассказал бы про суперскаляры: ++i можно сделать за пару тактов, а i++ за один. Прав я или нет? Из контекста зависит.
все зависит от контекста, но лучше использовать ++i, когда вы просто увеличиваете счетчик, и вам не нужно старое значение i. Для простых типов скорость выполнения и использование памяти не так критично, а вот если на более сложных объектах это может быть критично.
«далай вот так!» — А почему?
А потому, что i++ порождает 2 объекта. Условно old-i и new-i. А ++i порождает всего один — new-i.

Так доходчиво?
Так доходчиво. Никогда бы не подумал, что оператор ++ имеет смысл применять к объектам. Не сочтите за дерзость, просто из любопытства, А зачем?..
Разные бывают цели и задачи, ну и как пример: итератор.
по идее, оптимизатор должен эти ситуации разбирать, и когда значение не нужно, то код i++ и ++i породит одни и те же инструкции.
UFO just landed and posted this here
Какого чёрта вас заминусовали? Всё ж ведь правильно говорите.
Держите плюс.
>>человека нужно оценивать не за сами знания, а за способность эти знания усваивать

Человека — да, а работника — по совокупности.

Вы бы наверное, не хотели, чтобы вас лечил ничего не знающий медик, но с очень хорошими способностями :)
Знаете, если уж на то пошло, я предпочту, чтобы меня оперировал хирург, который ничего не понимает в медицине, но который успешно провёл десятки операций, нежели тот, у которого есть диплом.
Ну вот знание всяких фишечек есть косвенный способ проверить много ли операций провел «хирург»
В смысле есть диплом, но он ни разу не оперировал человека.
Нет, такие вопросы обычно проверяют глубину знаний, поверхностные это знания (то есть разобраться человек в чужом коде может, а деталей не знает), или более глубокие, когда человек знает подробности реализации и во что этот код превратит компилятор.
На вопрос: «А что будет?». Надо отвечать: «Отвалится тест».
Это вам не Евгения подкинула вопросец? :)
Нет, не Евгения. Слушай, а че ты мне не ответил в личке? Такое ощущение, что испугался жутко6)
Я переезжал на другой конец города, тырнета не было :) Сегодня отвечу
То, что Delegate не отличается MulticastDelegate — это особенности реализации, люди же преполагают различие с позиции логики. Не стоит упрекать людей в логичности и последовательности.

2. Событие нельзя запустить вне класса, в котором оно было объявлено (это самое важное отличие!!!)

В приведённом примере это условие не выполняется — метод OnDoWork объявлен открытым.

4. Событие всегда объявляется как «поле», а не свойство (add-remove не в счет).

И события, и свойства реализуются всегда через методы и возможно через вспомогательное поле для хранения данных (add и remove неожиданно обретают смысл, как и get, и set).

Рекомендуемая реализация вызова события такова:

protected virtual void OnDoWork(EventArgs e)
{
var doWork = DoWork;
if (doWork != null)
doWork(this, e);
}
Кстати, ответ на второй вопрос неверный. Например, Windows Forms и WPF просто не скомпилируются. Подробности можно узнать через Рефлектор.
Объясните уж, потрудитесь:)
Традиционно классы контролов содержат множество событий и не все из них имеют подписчиков, отчего иметь вспомогательное поле на каждое событие нецелесообразно, поэтому в указанных подсистемах фреймворка используются свои экономные/специальные модели хранения делегатов события. У всех событий переопределены методы add и remove, соответственно удаление ключевого слова event вызовет ошибку компиляции.

Кстати, когда подписчики не отписываются от события и живут короче, чем источник события, могут возникать утечки памяти, то есть подписчик больше не нужен, но источник продолжает хранить ссылку на него через делегат — в таких случаях рекомендуется хранить слабые ссылки (WeakReference) на делегаты подписчиков, а для этого опять же придётся переопределить методы add и remove, чтобы управлять списком слабых ссылок.
DoWork(null, EventArgs.Empty) при объявленном эвенте работать вне класса не будет — я это имел в виду.
UFO just landed and posted this here
Всё верно, но когда незнающий человек видит два класса, он предполагает, что между ними есть различие, потому что это логично.
Есть ещё одно отличие событий от делегатов — в интерфейсе можно объявить событие, а делегат нельзя.
Можно, но не как поле, а как свойство.
Обычно на собеседованиях такие вопросы задают специально подготовленные человеки. Например, ПМ. Которые сами программный код не пишут, но читают очень много всякой разной интересной литературы. Целей у таких вопросов обычно две.
1. Набить цену компании, дескать, какие у нас классные специалисты работают. «Работать в нашем банке — большая честь». То чего не знаешь ты, знаем мы. Ты много узнаешь, работая у нас.
2. Опустить соискателя и скинуть ему оклад. Чтобы даже мысли не появилось просить туже зп, что была указана в тексте вакансии.

Подобные вопросы говно. И задаются говноменеджерами и иже с ними. Когда мне нужно описать событие, я пользуюсь написанным code snippet'ом. Мне глубоко наплевать какая разница между явным объявлением события через ключевое слово event и без оного. Я знаю, что через event работает и знаю, как работает. Больше меня вопрос объявления событий не колышет и не должен колыхать. Если у ПМа есть время, пускай читает разные полезные статьи и книжки на тему.

Подобные вопросы не имеют ничего общего с реальностью и, следовательно, ничего не могут сказать о соискателе, кроме того как много книжек он прочитал перед собеседованием.
Думаю, подобный вопрос мог бы проканать на собеседовании нового ПМа. Нашли сами? Вот и используйте при собственных собеседованиях.
Так и хочется запастись парой каверзных вопросов, чтобы на собеседовании смело можно было спросить «А Вы сами-то много знаете?»
Такой вопрос говорит о том, насколько человек заинтересован в технологии, которую использует.
Если вы знаете, как работают события, вы знаете и ответ на этот вопрос, это несложно.
Зато он проверяет одновременно понимание событий и способность сообразить ответ на новый, неизвестный ранее вопрос.

У меня очень хорошая команда, в том числе потому что любой из них не стал бы кричать про такую задачу «а зачем это вообще надо?!», а ответил бы, или хотя бы задумался. Потому что приятно работать с людьми, которым интересно, а не просто хочется получить очередную зарплату.

Конечно, нельзя по такому вопросу решать исход собеседования или оклад, но бесполезным я бы его тоже не назвал.
Вы, похоже, из тех людей, кто любят нажимать галки и расставлять свойства через дизайнер, не задумываясь над тем, что же означает то или иное действие. Вопрос про эвенты и делегаты — это вопрос именно на понимание платформы. Хороший программист тем и хорош, что знает внутренности, внутренний мир, когда разрабатывает свои программы, чтобы он смог извлекать максимальную выгоду из платформы.

Платформа.нет отупляет. Вы бы не смогли так работать, как вы пишете, например, на плюсах.
>Платформа.нет отупляет.

Где-то я уже что-то подобное слышал… С — отупляет, писать надо на asm!

Боже, какая ностальгия!..
.Нет тут ни при чем. Все дело в органической прослойке между креслом и монитором ;)
Не буду обобщать, но знание именно этого вопроса в определенной ситуации будет крайне полезным. Представьте, что ваш класс должен содержать десятки событий (как Control в WinForms). Если объявить все через event, то компилятор добавит к классу столько же приватных делегатов, которые в сумме будут кушать довольно много памяти, особенно если таких объектов не один или два, а также десятки. При этом маловероятно, что во время запуска понадобится подписаться на абсолютно все события в один момент. В результате получаем недовольных пользователей, у которых складывается мнение о .NET как о тормозной и неэффективной платформе.

P. S. Читайте Рихтера.
В случае работы с большим количеством объектов, поддерживающих огромное число свойств, я использую переписанный EventBroker из CAB. Больше вопрос событий мне не интересен. Они используются только в случае маленьких объектов в таких же маленьких приложениях.
По поводу WinForms. В таких приложениях также используется EventBroker, а в случае если идет работа над компонентом, наследуемым от System.ComponentModel.Component, то все события кладутся в EventHandlerList Events.

Рихтер классный чувак. Не понимаю только как вы его связали с начальной инициализацией конкретного приложения. То, что платформа генерирует дополнительные методы на каждое событие — не проблема. Проблема в том, что ваше приложение некорректно инициализируется.
Кстати как раз что стоит спросить при собеседовании паттэрны проектирования и их реализация на .NET, как тот же EventBroker можно реализировать. Пользы с такого разработчика будет больше.
> Подобные вопросы не имеют ничего общего с реальностью и, следовательно, ничего не могут сказать о соискателе, кроме того как много книжек он прочитал перед собеседованием.

Хехе, наоборот, именно такие вопросы показывают, знает ли человек подробности работы компилятора и устройство фреймворка, или же только галочки научился ставить в вижуал студии.

> Когда мне нужно описать событие, я пользуюсь написанным code snippet'ом. Мне глубоко наплевать какая разница между явным объявлением события через ключевое слово event и без оного.

Вот, я всегда говорил что МС и ее продукты ориентируется на разработчиков с самым низким уровнем знаний (начиная с того момента как они стали продвигать среду разработки приложений, а потом и веб-приложений, на прости господи, Бейсике), а мне еще не верят!
> Хехе, наоборот, именно такие вопросы показывают, знает ли человек подробности работы компилятора и устройство фреймворка, или же только галочки научился ставить в вижуал студии.

Я переписал EventBroker под свои нужды так, чтобы обойтись без явного объявления событий, больше этот вопрос меня не беспокоит. Совсем. Знания работы компилятора это отличный навык. *Утрирую*, но вам он в описываемом качестве понадобится, когда вы будете писать драйвера под Singularity. Вероятно.

> МС и ее продукты ориентируется на разработчиков с самым низким уровнем знаний

Простите, я немного сконфужен *shy*. Тогда кто? Скажите кто ориентируется на разработчиков с хорошим уровнем знаний? То, что MS предлагает мощные инструменты решения некоторых общих задач в разы, упрощая разработку программного кода, не говорит о том, что пользователи этих инструментов плохие специалисты. То, что любой хороший инструмент расхалаживает пользователя — факт, не спорю. Но расхалаживает ровно настолько насколько это необходимо. Возьмите у дедушки в деревне двуручную пилу и привезите из леса возок дров. Я возьму Husqvarna и пикап. Судя по вашему посту, я узнаю о себе еще много нового.
Так, вы абсолютно правы. Полагаю, тут идея в том, что среди тех, кто ответит на этот вопрос «крутых спецов» будет заметно больший процент. Потому и задают вопросы на абсолютно непрактичные навыки. Да, они нафиг не нужны, но среди тех кто отсеется, шлака будет намногооо меньше.
Напомнило как я сдавал c++ в универе. У меня была реализована задачка на два листа (на бумаге нужно было писать на экзамене), преподаватель выбрал самое длинное условие в каком-то if-е и зачеркнул часть, затем спросил: «А вот так будет работать? А почему?».
Пост классный, благодарю! Сам люблю «головоломки», но согласен с большинством комментариев о том, что настолько углубляться в платформу не стоит вашего времени, укрепляйте лучше фундаментальные знания. На собеседовании такой вопрос можно смело игнорировать, ибо полезной нагрузки никакой не несёт
Есть одно неочевидное, но интересное различие.
Если в коде ASP.NET формы/контрола объявить событие (т.е. указать event), то в разметке появляется возможность декларативно указать для этого события делегат.
К примеру если объявить событие public event MyEventHandler MyEvent; то в aspx/ascx-файле у контрола можно декларативно прописать OnMyEvent="...". (Обратите внимание, что ASP.NET добавляет приставку On.)
Для простых полей делегатов такого нет.
Ах да, поэтому дополнение к ответу на вопрос 2: если в ASP.NET проекте есть декларативное подписывание на события, то возникнет ошибка компиляции.
Хм, перепроверил эти сведения, оказалось, что ошибка компиляции НЕ возникает (компилятор просто игнорирует этот атрибут, хотя вполне вероятно это где-то настраивается).
Поэтому фактической привязки уже не происходит, и обработчик не будет вызываться. Также в разметке OnMyEvent пропадает из intellisense-списка редактора.

Подытожим: в ASP.NET декларативно можно подписываться только на события (event) через специальный атрибут с префиксом On.

Такая уличная магия. :)
Что читать, чтобы такие вопросы не ставили в тупик?
Хабрахабр? Шучу.

Наверное все же стоит тщательно заботать рихтеровский CLR via C#.
Книжку уже посоветовали.

А для дальнейших изысканий:
DotNetKicks.com — это коллективный блог ссылок. И здесь индивидуальные: nayyeri.net/blog/my-favorite-.net-link-blogs/

Блоги ссылок удобны тем, что содержат ссылки на самые интересные статьи самых разных авторов, легко расширяет кругозор.
Миф о том что Delegate может содержать только один элемент в инвокейшн листе пошел от MSDN:
MulticastDelegate Class
Represents a multicast delegate; that is, a delegate that can have more than one element in its invocation list.
(http://msdn.microsoft.com/en-us/library/system.multicastdelegate.aspx)
Ну да, но в самом clr нет derivable объектов, напрямую наследуемых от Delegate:)
так я и не спорю :)
Дело в том, что мсдн тут не причем — про invocation list там четко сказано, что same is for Delegate object:) Просто, «Delegate» — это «MulticastDelegate», но сам class Delegate скрыт для исползования — чертовщина похлеще вия.

Тем не менее, люди путают.
Чтобы значть ответы на такие вопросы, надо не пытаься заучивать определения и различия (в которых не видно с ходу какой-то логики), а надо просто знать, как это реализовано на уровне компилятора и интепретатора IL.
Пример интересный, но для собеседования этот вопрос не подходит.
Допустим, кандидат не знает ответ на вопрос. Значит ли это что он плохой .net-программист? нет, не значит, ровно как и не значит что плохой. Если он знает ответ на вопрос (думаю что это меньше 0,5% кандидатов), то скорее всего, он либо очень глубоко знает именно этот топик, либо (скорее всего) увидел пример в инете.
Ну, ведь собеседование не состоит из одного вопроса, верно?
Правильный ответ с точки зрения разработчика API тут один:

Если это Event — Выражение a.DoWork = null вызовет ошибку компиляции.
Если это Делегат — Выражение a.DoWork = null СОТРЁТ все подписавшиеся обработчики, что не допустимо для API.

Попросил запостить приятель, которому нужен инвайт =)
Почему не допустимо? Что в вашем понимании здесь API?
Вы пишете графический компонент, у этого компонента есть к примеру события.
Ваш компонент через public API, должны иметь возможность вызывать другие разработчики. Если вы используете события, это не позволит другим разработчикам СТЕРЕТЬ, цепочку подписавшихся обработчиков.

То есть:

form.Load += Dev1Handler
form.Load += Dev2Handler


а потом какой-то Вася решает, а ну его нах, form.Load = null!!!
Event защитит от этого не дав Васе стететь цепочку по глупости, делегат — позволит это сделать.

Кроме-того, часто густо сами разработчики компонентов и API подписываються на свои же события. Тем самым использование открытых делегатов в корне не верно для написания API или любых открытых компонентов.

Именно с этой целью в .NET и введены события, для защиты API от кривого использования.

public class A
{
public void OnDoWork()
{
if (DoWorkEvent != null)
DoWorkEvent(this, EventArgs.Empty);
}

public event EventHandler DoWorkEvent;
public EventHandler DoWorkDelegate;
}

A a = new A();
a.DoWorkEvent = null; // Compilation error
a.DoWorkDelegate = null;
ваще отлично:) прекрасное практическое объяснение на примере.
Если хочешь, можешь скинуть инвайт человеку это написавшему. podpalch@gmail.com
У мну нет кармы =(
Я то может и хочу, но у меня тоже нет кармы:)
в общем, карма появилась, инвайт выслал на указанный мейл.
Спасибо большое. Создал аккаунт.
У меня первое скомпилилось нормально. ЧЯДНТ?
Попробуй то, что выше — поймёшь.
А, в плане обращения снаружи. Да, это так, add-remove и есть аналоги getter/setter, единственно доступные снаружи для события.
И соответсвенно, не позволяющие вмешиваться в логику работы компонента, в отличие от мультикаст делегата.

А вопрос то хороший, отлично отсеивает.
Я видел много разработчиков которые всё ещё используют ArrayList вместо List, о Dictionary, Hashable даже не знают. Знание generic тоже очень полезно. Знать о существовании интерфейсов IComparable, IDisposable, IEnumerable, IConvertible, TypeConverter и т. д., уметь их правильно реализовать.
А ваш пример как указали выше больше показать крутость спрашивающего с реальной жизнью связь чисто теоретическая.
ArrayList'ы используют как правило те кто начинал ещё с 1 .NET и лениться почитать про generic'и. А про вопрос, этот вопрос вполне актуальнен, особенно если человек которого нанимают, должен уметь писать открытые API.
Совершенно согласен. Я бы не ответил на этот вопрос, хотя в моем портфолио крупные проекты на .NET.
Only those users with full accounts are able to leave comments. Log in, please.