Аргументы у делегатов типов для событий
От: naf2000  
Дата: 11.11.10 06:23
Оценка:
вот здесь прочел следующее:

Создавая событие в компонентах и control-ах, старайтесь описывать их по следующей схеме. Определите два параметра с именами sender и e. Параметр sender описывает объект, инициировавший событие, и всегда должен быть типа object, даже если возможно использование более конкретного типа. Второй параметр, e, должен содержать состояние и дополнительную информацию, соответствующую событию. Этот параметр должен быть конкретного типа, относящегося к событию.

Собственно, а почему sender должен быть именно только object? Или это касается только контролов и компонент, а произвольных классов не касается?
Re: Rx
От: Qbit86 Кипр
Дата: 11.11.10 06:27
Оценка:
Здравствуйте, naf2000, Вы писали:

N>Или это касается только контролов и компонент, а произвольных классов не касается?


Для произвольных классов стоит задуматься об использовании Rx.
Глаза у меня добрые, но рубашка — смирительная!
Re: Аргументы у делегатов типов для событий
От: _FRED_ Черногория
Дата: 11.11.10 06:33
Оценка: +1
Здравствуйте, naf2000, Вы писали:

N>вот здесь прочел следующее:

N>

N>Создавая событие в компонентах и control-ах, старайтесь описывать их по следующей схеме. Определите два параметра с именами sender и e. Параметр sender описывает объект, инициировавший событие, и всегда должен быть типа object, даже если возможно использование более конкретного типа. Второй параметр, e, должен содержать состояние и дополнительную информацию, соответствующую событию. Этот параметр должен быть конкретного типа, относящегося к событию.

N>Собственно, а почему sender должен быть именно только object? Или это касается только контролов и компонент, а произвольных классов не касается?

Для унификации. Если хочется иметь в обработчике типизированный sender, можно передавать его через EventArgs.
Help will always be given at Hogwarts to those who ask for it.
Re: Аргументы у делегатов типов для событий
От: naf2000  
Дата: 11.11.10 07:00
Оценка: +1
и еще, если event такой умный, что его вызов есть последовательный вызов всех соответствующих методов его подписчиков, то на кой надо писать так:
if (MouseMove != null)
      MouseMove(this, e);

почему нельзя было проще реализовать:
MouseMove(this, e);

если никто не подписан, то и никто не вызван
Re: Аргументы у делегатов типов для событий
От: belnetmon Беларусь  
Дата: 11.11.10 07:22
Оценка:
N>Собственно, а почему sender должен быть именно только object?

Чтоб не тащить зависимости по проектам
Re[2]: Аргументы у делегатов типов для событий
От: naf2000  
Дата: 11.11.10 07:41
Оценка:
Здравствуйте, belnetmon, Вы писали:

N>>Собственно, а почему sender должен быть именно только object?


B>Чтоб не тащить зависимости по проектам


ну да, только вы все равно будете все это приводить к типу
Re[2]: Аргументы у делегатов типов для событий
От: Qbit86 Кипр
Дата: 11.11.10 07:56
Оценка: -1
Здравствуйте, naf2000, Вы писали:

N>почему нельзя было проще реализовать:

N>
MouseMove(this, e);

N>если никто не подписан, то и никто не вызван

Это очень правильный вопрос!

N>и еще, если event такой умный, что его вызов есть последовательный вызов всех соответствующих методов его подписчиков, то на кой надо писать так:

N>
N>if (MouseMove != null)
N>      MouseMove(this, e);
N>


Даже не так. Надо писать:
var handler = MouseMove;
if (handler != null)
    handler(this, e);

Обсуждение этого есть у Рихтера или во «Framework Design Guidelines».

Так что лучше по возможности использовать простой и понятный IObservable<T> из Rx вместо event'ов.
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: Аргументы у делегатов типов для событий
От: _FRED_ Черногория
Дата: 11.11.10 08:37
Оценка: +1
Здравствуйте, naf2000, Вы писали:

N>и еще, если event такой умный, что его вызов есть последовательный вызов всех соответствующих методов его подписчиков, то на кой надо писать так:

N>if (MouseMove != null)
N>      MouseMove(this, e);

N>почему нельзя было проще реализовать:
N>MouseMove(this, e);

N>если никто не подписан, то и никто не вызван

Потому что это пришлось бы поддерживать не для event-ов, а для любых переменных типа Delegate. И получилось бы не очень стройно по сравнению с использованием всех остальных переменных. Если это сильно напрягает, можно написать хелпер
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Аргументы у делегатов типов для событий
От: Sinix  
Дата: 11.11.10 08:44
Оценка: +1
Здравствуйте, Qbit86, Вы писали:

Q>Так что лучше по возможности использовать простой и понятный IObservable<T> из Rx вместо event'ов.

RX и эвенты решают слегка разные задачи, и пропихивать везде RX (этож новая фича!) не менее глупо, чем пропихивать везде эвенты (они ж всегда были!).
Re[4]: Аргументы у делегатов типов для событий
От: Qbit86 Кипр
Дата: 11.11.10 08:52
Оценка:
Здравствуйте, Sinix, Вы писали:

S>RX и эвенты решают слегка разные задачи,


GoF-паттерн Observer.

S>и пропихивать везде RX (этож новая фича!) не менее глупо, чем пропихивать везде эвенты (они ж всегда были!).


Везде не нужно.
Глаза у меня добрые, но рубашка — смирительная!
Re[3]: Аргументы у делегатов типов для событий
От: Qbit86 Кипр
Дата: 11.11.10 09:00
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Потому что это пришлось бы поддерживать не для event-ов, а для любых переменных типа Delegate.


То есть не по объективным причинам, а по причинам совместимости с сомнительными архитектурными решениями при разработке языка. События используются в сценариях, отличных от общих сценариев использования делегатов. Но тем не менее создатели языка решили их скрестить, пожертвовав чистотой и удобством использования.
Глаза у меня добрые, но рубашка — смирительная!
Re[4]: Аргументы у делегатов типов для событий
От: _FRED_ Черногория
Дата: 11.11.10 09:05
Оценка:
Здравствуйте, Qbit86, Вы писали:

_FR>>Потому что это пришлось бы поддерживать не для event-ов, а для любых переменных типа Delegate.


Q>То есть не по объективным причинам, а по причинам совместимости с сомнительными архитектурными решениями при разработке языка.


Для вас так важно назвать данное решение "сомнительным"?

Q>События используются в сценариях, отличных от общих сценариев использования делегатов. Но тем не менее создатели языка решили их скрестить, пожертвовав чистотой и удобством использования.


Я с таким мнением "создателей языка" пока не знаком
Help will always be given at Hogwarts to those who ask for it.
Re[5]: Аргументы у делегатов типов для событий
От: Sinix  
Дата: 11.11.10 09:24
Оценка:
Здравствуйте, Qbit86, Вы писали:

S>>RX и эвенты решают слегка разные задачи,

Q>GoF-паттерн Observer.
Поясните плиз, что вы хотели сказать. С учётом этого
Автор: XopoSHiy
Дата: 14.04.10
Re[5]: Аргументы у делегатов типов для событий
От: Qbit86 Кипр
Дата: 11.11.10 09:25
Оценка: +1
Здравствуйте, _FRED_, Вы писали:

_FR>Для вас так важно назвать данное решение "сомнительным"?


Я просто констатировал факт, что дёргание ивентов — тёмный уголок в C#, причём это оправдывается соображениями типа «так вышло».

Чего я хочу как автор сендера: чтобы уведомление подписчиков о новом событии, ошибке или окончании потока событий выполнялось просто и прозрачно, без приседаний с сохранением временных ссылок, проверками их на null, etc.

Чего я хочу как автор подписчика: чтобы при подписке мне возвращался токен, с помощью которого я могу отписаться в RAII-стиле, без указания своих обработчиков справа от «-=». Вообще замечательно, если с потоком событий я могу работать как с push-коллекцией в привычном LINQ-подходе.

Стандартный синтаксис event'ов этим требованиям не удовлетворяет. Всякие weak event pattern'ы и прочие богомерзкие извращения использовать желания нет.
Глаза у меня добрые, но рубашка — смирительная!
Re[6]: Observer
От: Qbit86 Кипр
Дата: 11.11.10 09:28
Оценка:
Здравствуйте, Sinix, Вы писали:

S>>>RX и эвенты решают слегка разные задачи,

Q>>GoF-паттерн Observer.
S>Поясните плиз, что вы хотели сказать. С учётом этого
Автор: XopoSHiy
Дата: 14.04.10
:)


В «этом» обсуждался Visitor, а не Observer.
Глаза у меня добрые, но рубашка — смирительная!
Re[7]: Observer
От: Sinix  
Дата: 11.11.10 09:44
Оценка:
Здравствуйте, Qbit86, Вы писали:

S>>>>RX и эвенты решают слегка разные задачи,

Q>>>GoF-паттерн Observer.
S>>Поясните плиз, что вы хотели сказать. С учётом этого
Автор: XopoSHiy
Дата: 14.04.10

Q>В «этом» обсуждался Visitor, а не Observer.
Имел в виду исключительно первый пост. Конкретно — часть "об излишней любви к паттернам ради паттернов".

По-прежнему интересует: как ваше утверждение "и эвенты и IObservable можно обозвать реализацией паттерна обозреватель" соотносится с моим "RX и эвенты решают слегка разные задачи"
Re[8]: Observer
От: Qbit86 Кипр
Дата: 11.11.10 09:53
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Имел в виду исключительно первый пост. Конкретно — часть "об излишней любви к паттернам ради паттернов".


О «паттернах ради паттернов» речь не идёт, а тем более о любви к ним.

Не нравится «Observer/Observable», называй их «Receiver/Sender», «Listener/Notifyer», «Subscriber/Publisher», you name it.

S>По-прежнему интересует: как ваше утверждение "и эвенты и IObservable можно обозвать реализацией паттерна обозреватель" соотносится с моим "RX и эвенты решают слегка разные задачи" :???:


Ну, я не считаю, что они решают разные задачи.
Глаза у меня добрые, но рубашка — смирительная!
Re[9]: Observer
От: Sinix  
Дата: 11.11.10 10:11
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Ну, я не считаю, что они решают разные задачи.

Во-первых:
RX хорош для ленивой обработки последовательностей, особенно с LINQ.

Эвенты — для непосредственного реагирования на события аля
      Console.CancelKeyPress += (sender, e) => e.Cancel = false;

Для подобных задач RX будет оверкиллом.

Во вторых, RX и эвенты превосходно уживаются вместе.
Re[10]: Observer
От: Qbit86 Кипр
Дата: 11.11.10 10:26
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Во-первых:

S>RX хорош для ленивой обработки последовательностей, особенно с LINQ.

Полностью согласен.

S>Во вторых, RX и эвенты превосходно уживаются вместе.


Да, и это замечательно.

S>Эвенты — для непосредственного реагирования на события аля

S>
Console.CancelKeyPress += (sender, e) => e.Cancel = false;


Ну это совсем простой пример. В случае, когда источник событий живёт дольше подписчиков, нужно заморачиваться с потенциальными утечками наблюдателей, хранением ссылки на обработчик с целью отписки, etc.

S>Для подобных задач RX будет оверкиллом.


Да, в условиях использования большого количества библиотек и фреймворков (особенно GUI-), завязанных на классические события, притягивать Rx-прослойку за уши к каждому событию нецелесообразно. Но это не из-за того, что у них цели разные.
Глаза у меня добрые, но рубашка — смирительная!
Re[6]: Аргументы у делегатов типов для событий
От: _FRED_ Черногория
Дата: 11.11.10 11:21
Оценка:
Здравствуйте, Qbit86, Вы писали:

_FR>>Для вас так важно назвать данное решение "сомнительным"?


Q>Я просто констатировал факт, что дёргание ивентов — тёмный уголок в C#, причём это оправдывается соображениями типа «так вышло».


"Дёргание" вовсе не тёмный и в никаких оправданиях не нуждается.

Q>Чего я хочу как автор сендера: чтобы уведомление подписчиков о новом событии, ошибке или окончании потока событий выполнялось просто и прозрачно, без приседаний с сохранением временных ссылок, проверками их на null, etc.


Это делается очень просто:
  для EventHandler<>
  [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Event")]
  [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
  public static partial class Event
  {
    #region Methods

    [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = Justifications.HelperForEvent)]
    public static bool Raise<TEventArgs>(this EventHandler<TEventArgs> handler, object sender, TEventArgs args) where TEventArgs : EventArgs {
      if(handler != null) {
        handler(sender, args);
        return true;
      }//if

      return false;
    }

    [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = Justifications.HelperForEvent)]
    [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = Justifications.ParameterIsValidated)]
    public static bool Raise<TEventArgs>(this EventHandler<TEventArgs> handler, object sender, Func<TEventArgs> args) where TEventArgs : EventArgs {
      Argument.NotNull(args, "args");

      if(handler != null) {
        var e = args();
        handler(sender, e);
        return true;
      }//if

      return false;
    }

    #endregion Methods
  }

  для остальных делегатов в mscorlib и System
<#@ template language="C#" hostspecific="True" #>
<#@ output extension=".g.cs" #>
<#@ assembly name="System.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
// ----------------------------------------------------------------------------
// <autogenerated>
//   This file was generated using <#= System.IO.Path.GetFileName(Host.TemplateFile) #>.
//   Any changes made manually will be lost next time the file is regenerated.
// </autogenerated>
// ----------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace GExtensions
{
  partial class Event
  {
    #region Methods
<# RaiseStandardHandlers(typeof(int).Assembly); /* mscorlib */ #>
<# RaiseStandardHandlers(typeof(TypeDescriptor).Assembly); /* System */ #>

    #endregion Methods
  }
}
<#+ 
  private void RaiseStandardHandlers(Assembly assembly) {
    if(assembly == null) {
      throw new ArgumentNullException("assembly");
    }//if

    var types = from type in assembly.GetExportedTypes()
                where typeof(Delegate).IsAssignableFrom(type)
                where !type.IsAbstract
                where !type.IsGenericTypeDefinition
                let invoke = type.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance)
                where invoke != null
                where invoke.ReturnType == typeof(void)
                let parameters = invoke.GetParameters()
                where parameters != null && parameters.Length == 2
                where Array.TrueForAll(parameters, p => !p.IsOut && !p.IsLcid && !p.IsRetval)
                where parameters[0].ParameterType == typeof(object)
                let args = parameters[1].ParameterType
                where typeof(EventArgs).IsAssignableFrom(args)
                select Tuple.Create(type, args);

    foreach(var type in types) {
      Raise(type.Item1.FullName, type.Item2.FullName);
    }//for
  }

  private void Raise(string handler, string args) {
#>

    #region <#= handler #>

    [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = Justifications.HelperForEvent)]
    public static bool Raise(this <#= handler #> handler, object sender, <#= args #> args) {
      if(handler != null) {
        handler(sender, args);
        return true;
      }//if

      return false;
    }

    [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = Justifications.HelperForEvent)]
    [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "2", Justification = Justifications.ParameterIsValidated)]
    public static bool Raise(this <#= handler #> handler, object sender, Func<<#= args #>> args) {
      Argument.NotNull(args, "args");

      if(handler != null) {
        var e = args();
        handler(sender, e);
        return true;
      }//if

      return false;
    }

    #endregion <#= handler #>
<#+
  }
#>


У каждого (у многих) делегата появляется метод Raise который решает и проблему проверки на null и даже потокобезопастность разруливает.

Q>Чего я хочу как автор подписчика: чтобы при подписке мне возвращался токен, с помощью которого я могу отписаться в RAII-стиле, без указания своих обработчиков справа от «-=». Вообще замечательно, если с потоком событий я могу работать как с push-коллекцией в привычном LINQ-подходе.

Q>Стандартный синтаксис event'ов этим требованиям не удовлетворяет. Всякие weak event pattern'ы и прочие богомерзкие извращения использовать желания нет.

Чего в ваших выкладках не хватает — так это ширины взгляда. Как в такой моделе создавать подписчики из дизайнера?
Help will always be given at Hogwarts to those who ask for it.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.