Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ionoy, Вы писали:
I>>Удобнее тем, что внешнему коду не нужно знать конкретный тип обработчика, чтобы отменить операцию. S>Что такое "конкретный тип обработчика"?
Потому что источники событий могут быть разные (Event1, Event2 и любая другая подписка).
Получается, что методу отписки нужно знать не только тип обработчика, но и само событие от которого нужно отписаться. Далеко не всегда есть возможность эту информацию предоставить.
S>Непонятно, почему именно Disposable. S>Почему вы не хотите комбинировать, например, Action.
Из-за разных наборов параметров.
Здравствуйте, ionoy, Вы писали:
S>>Непонятно, почему именно Disposable. S>>Почему вы не хотите комбинировать, например, Action. I>Из-за разных наборов параметров.
Дополню:
И необходимости передавать источник. От самого Action толку мало, в отличие от IDisposable.
Здравствуйте, ionoy, Вы писали:
I>Дополню: I>И необходимости передавать источник. От самого Action толку мало, в отличие от IDisposable.
А, я, наверное, непонятно выразился.
вот что я имел в виду:
Как видим, внешнему коду вообще не нужно знать ни тип обработчика, ни конкретное событие. Достаточно позвать делегат, который ему вернули, в тот момент, когда вы хотели вызывать IDisposable.Dispose.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Как видим, внешнему коду вообще не нужно знать ни тип обработчика, ни конкретное событие. Достаточно позвать делегат, который ему вернули, в тот момент, когда вы хотели вызывать IDisposable.Dispose.
Примерно так оно и работает внутри. Есть, например, удобный метод:
Как я это вижу, у IDisposable есть несколько преимуществ перед Action:
1. На основании этого интерфейса можно создать готовую библиотеку реализаций IDisposable, как сделали в Rx. Такие объекты предоставляют дополнительную функциональность для кода выдающего подписку, а для клиентов всё тот же IDisposable. Про некоторые готовые реализации опять же здесь: http://synchronicity-life.blogspot.com/2011/12/idisposable-implementations-in-reactive.html
2. IDisposable — это распространённый шаблон проектирования. Иногда бывает удобно локализовать подписку с помощью using.
3. IDisposable семантически лучше подходит на роль отписчика, чем Action
I>Как я это вижу, у IDisposable есть несколько преимуществ перед Action:
Ну так и используйте его, если в вашей инфраструктуре он удобнее.
Лично мне более удобными кажутся weak events, т.к. сама необходимость следить за отпиской напрягает. Независимо от того, используется ли "честный" OnClick -=, Action, или IDisposable.
Я очень часто сталкивался с тем, что нам нужен "observer, который следит, покуда жив", а не "observer, который жив, покуда следит".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
I>>Как я это вижу, у IDisposable есть несколько преимуществ перед Action: S>Ну так и используйте его, если в вашей инфраструктуре он удобнее. S>Лично мне более удобными кажутся weak events, т.к. сама необходимость следить за отпиской напрягает. Независимо от того, используется ли "честный" OnClick -=, Action, или IDisposable. S>Я очень часто сталкивался с тем, что нам нужен "observer, который следит, покуда жив", а не "observer, который жив, покуда следит".
Многие Observable так и устроены.
Например, такой код:
stream.Take(3).Subscribe(x => DoSomething(x))
сам отпишет подписчика. IDisposable нужен только в тех случаях, когда ты сам хочешь выбирать момент где переставать следить за потоком.
Здравствуйте, ionoy, Вы писали: I>сам отпишет подписчика.
Это понятно. Есть обратные ситуации — datasource.OnChange += form1.Refresh навсегда удержит форму в памяти.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ionoy, Вы писали: I>>сам отпишет подписчика. S>Это понятно. Есть обратные ситуации — datasource.OnChange += form1.Refresh навсегда удержит форму в памяти.
Так ведь можно отписаться по необходимости. Или я чего-то не понимаю?
Здравствуйте, ionoy, Вы писали: S>>Это понятно. Есть обратные ситуации — datasource.OnChange += form1.Refresh навсегда удержит форму в памяти. I>Так ведь можно отписаться по необходимости. Или я чего-то не понимаю?
Что значит "по необходимости"? Как вы определите момент необходимости?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ionoy, Вы писали: S>>>Это понятно. Есть обратные ситуации — datasource.OnChange += form1.Refresh навсегда удержит форму в памяти. I>>Так ведь можно отписаться по необходимости. Или я чего-то не понимаю? S>Что значит "по необходимости"? Как вы определите момент необходимости?
Вопрос был в том, что привязка навсегда удержит форму в памяти. Если есть такая проблема, значит когда-то эта форма перестаёт быть нужной? Обычно момент удаления формы более или менее детерминирован.
Ничего не понял. По ссылке — абсолютно работоспособный пример. На событие подписывается ровно одна функция.
В этом коде — тоже. На какой вопрос вы отвечаете — непонятно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, ionoy, Вы писали: I>Вопрос был в том, что привязка навсегда удержит форму в памяти. Если есть такая проблема, значит когда-то эта форма перестаёт быть нужной?
Обычно (в среде с недетерминистической финализацией) объект перестаёт быть нужен тогда, когда последняя ссылка на него выходит из области видимости.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ionoy, Вы писали: I>>Вопрос был в том, что привязка навсегда удержит форму в памяти. Если есть такая проблема, значит когда-то эта форма перестаёт быть нужной? S>Обычно (в среде с недетерминистической финализацией) объект перестаёт быть нужен тогда, когда последняя ссылка на него выходит из области видимости.
Ссылка сама по себе не выходит из области видимости, какой-то код управляет этим процессом, в любом случае. Может просто пример с формой неудачный, т.к. там нет проблем отследить закрытие
Здравствуйте, ionoy, Вы писали:
I>Ссылка сама по себе не выходит из области видимости, какой-то код управляет этим процессом, в любом случае.
Да ладно!
Ещё как выходит. Если бы это было не так, то нам вообще бы не потребовался сборщик мусора — мы всегда бы знали, в какой момент пора звать деструктор и освобождать память
I>Может просто пример с формой неудачный, т.к. там нет проблем отследить закрытие
Да. С формой пример не совсем удачный, т.к. в ней есть явный Dispose, в котором можно сделать отписку и полагаться на компонентную модель в контроле времени жизни. И тем не менее — ошибку типа "забыл отписаться" сделать очень легко. Эта возможность граблей никуда не денется от того, что оператор += будет возвращать что-то другое. Нам всё равно нужно куда-то записывать ссылку, либо на IDisposable, который надо не забыть отдиспозить, либо на хэндлер, который нужно отписать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ionoy, Вы писали:
I>>Ссылка сама по себе не выходит из области видимости, какой-то код управляет этим процессом, в любом случае. S>Да ладно! S>Ещё как выходит. Если бы это было не так, то нам вообще бы не потребовался сборщик мусора — мы всегда бы знали, в какой момент пора звать деструктор и освобождать память
А можно пример, где ссылка сама по себе выходит из области видимости, но при этом остаётся в памяти из-за привязки к событию?
I>>Может просто пример с формой неудачный, т.к. там нет проблем отследить закрытие S>Да. С формой пример не совсем удачный, т.к. в ней есть явный Dispose, в котором можно сделать отписку и полагаться на компонентную модель в контроле времени жизни. И тем не менее — ошибку типа "забыл отписаться" сделать очень легко. Эта возможность граблей никуда не денется от того, что оператор += будет возвращать что-то другое. Нам всё равно нужно куда-то записывать ссылку, либо на IDisposable, который надо не забыть отдиспозить, либо на хэндлер, который нужно отписать.
Это верно, ошибиться можно. Другое дело, что про эти грабли разве что глухой не слышал.