Подтвердить что ты не робот

Использование EventArgs для передачи информации обратно в вызывающий класс

Не рекомендуется изменять EventArgs в обработчиках событий для передачи информации обратно в класс, вызывающий событие?

Например, если у меня есть класс связи низкого уровня, требующий проверки сертификата для SSL, но у него нет способа узнать, как выглядит действительный сертификат, поскольку это знание разных пользователей этого класса.

class ValidationEventArgs : System.EventArgs
{
    public X509Certificate Certificate { get; set; }
    public bool Valid { get; set; }
}

Затем в используемых объектах они подключаются к событию и проверяют его как-то изменяя флаг Valid, чтобы указать, является ли сертификат приемлемым или нет.

comms.ValidationEvent += CertValidationHandler;

void CertValidationHandler(ValidationEventArgs args)
{
    if (args.Certificate.Issuer.Contains(COMPANY_NAME)
        args.Valid = true;
}

Я нашел ссылки из EventArgs, которые используются таким образом, но я также видел, что люди говорят, что это не рекомендуется.

Изменить: Возможно, мне следует пояснить, что речь идет не о наследовании EventArgs, а о том, как использовать двунаправленный канал связи. Как отмечают другие, это приемлемо, и любой шум, который Google подбирает к противоположному, вероятно, просто люди, которые неправильно поняли/использовали концепцию и теперь имеют тот же личный крестовый поход, что и goto.

4b9b3361

Ответ 1

Задайте себе следующий вопрос: "Когда я публикую событие, хочу ли я, чтобы какой-либо подписчик изменял любые значения EventArgs"? Если ответ отсутствует, например. вы передаете информацию на основе readonly, затем делаете класс неизменным, однако, если вам нужна некоторая обратная связь от подписчика, тогда создайте свойства, которые необходимо изменить изменчивым.

Чтобы пояснить, в широковещательном примере мы хотим что-то сказать любому подписчику, но не позволяем им изменять значение.

public class ProgressEventArgs : EventArgs
{
    public ProgressEventArgs(int current)
    {
        this.Current = current;
    }

    public int Current { get; private set; }
}

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

public class FeedbackEventArgs : EventArgs
{
    public bool ShouldContinue { get; set; }
    public string Reason { get; set; }
}

Ответ 2

Вы можете использовать класс EventArgs с помощью подхода Generic Types. В этом примере я буду использовать класс Rect с типом возврата:

public EventHandler<Rect> SizeRectChanged;

Поднятие события:

if(SizeRectChanged != null){
   Rect r = new Rect(0,0,0,0);
   SizeRectChanged(this,r);
}

Прослушивание события:

anyElement.SizeRectChanged += OnSizeRectChanged;

public void OnSizeRectChanged(object sender, Rect e){
    //TODO abything using the Rect class
    e.Left = e.Top = e.Width = e.Height = 50;
}

Ответ 3

Мне не известно о какой-либо рекомендации против наследования с EventArgs; насколько я знаю, унаследовать от него - хорошая практика.

Как общий принцип, я предлагаю вам сделать неизменяемые производные классы. Это сделает намного безопаснее проходить между потоками, если вам нужно это сделать. Самый простой способ сделать это - объявить ваши свойства как { get; private set; } и только установить их в конструкторе. Очевидно, вы не можете этого сделать с конкретным вариантом использования, который у вас есть в вопросе, но вы должны делать это, когда это возможно.