C # Custom EventArgs Вопрос - PullRequest
2 голосов
/ 13 мая 2009

У меня есть пользовательская коллекция, к которой я добавляю событие ValidateItem. Это событие ValidateItem будет вызываться всякий раз, когда элемент добавляется или обновляется в пользовательской коллекции.

Я хочу позволить производным классам иметь возможность подписываться на событие и определять свою собственную логику того, является ли элемент «допустимым» и потенциально запрещать его добавление в коллекцию, если он «недействителен».

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

Мои пользовательские eventargs наследуются от CancelEventArgs, поэтому у меня есть возможность передать бит Cancel обратно вызывающей стороне, используя это. Но я никогда не встречал случаев, когда информация об ошибках (коды ошибок, сообщения и т. Д.) Передавалась бы таким образом, поэтому мне интересно, может быть, это не лучший подход.

Должен ли я просто добавить какие-либо данные об ошибках, которые я хочу передать обратно в мой класс пользовательских событий, есть ли веские причины для этого или против? или есть другие, лучшие способы сделать это?

Вот мой класс eventargs:

public delegate void ItemValidationEventHandler(object sender, ItemValidationEventArgs e);

public class ItemValidationEventArgs : CancelEventArgs
{
    public ItemValidationEventArgs(object item, ObjectAction state, EventArgs e)
    {
        Item = item;
        State = state;
        EventArgs = e;
    }

    public ItemValidationEventArgs(object item, ObjectAction state) : this(item, state, new EventArgs())
    {
    }

    public ItemValidationEventArgs() : this(null, ObjectAction.None, new EventArgs())
    {
    }

    // is there a better way to pass this info?
    public string ErrorMessage {get; set;}
    public int ErrorNumber {get;set;}

    public object Item { get; private set; }
    public ObjectAction State { get; private set; }

    public EventArgs EventArgs { get; private set; }
}

ОБНОВЛЕНИЕ: я полагаю, что другой вариант будет использовать что-то вроде этого:

virtual bool Validate(object item, ObjectAction action, out string errorMessage) 

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

Если у кого-нибудь есть идеи о плюсах и минусах каждого подхода, я бы хотел их услышать!

Спасибо, Max

Ответы [ 6 ]

3 голосов
/ 14 мая 2009

Использование событий для этого, вероятно, не лучший подход к проектированию.

Поскольку это наследующий класс, который будет переопределять это поведение, метод должен быть помечен как защищенный и виртуальный:

protected virtual bool Validate(object item);

Мне тоже не нравится использовать out для параметров, поэтому, следуя вашим начальным инстинктам для использования EventArgs, вам, вероятно, следует создать класс для инкапсуляции результатов вашей проверки.

Пример:

class ValidationResult
{
     public string ResultMessage{get;set;}
     public bool IsValid {get;set;}
}

Ваш метод будет тогда:

protected virtual ValidationResult Validate(object item)
{
   ValidationResult result = new ValidationResult();

   // validate and set results values accordingly

   return result;
}

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

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

1 голос
/ 13 мая 2009

Я не думаю, что то, что вы описываете, действительно соответствует наблюдателю, наблюдаемой модели, которую вы обычно видите с событиями.

Так как это производные классы, я бы, вероятно, обратился к виртуализации метода проверки объектов и к тому, чтобы дочерние элементы предоставили специальную процедуру проверки.

0 голосов
/ 13 мая 2009

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

Наконец, вместо создания собственного типа делегата ItemValidationEventHandler вы можете использовать EventHandler<T>, где T - это тип параметра EventArgs.

Кроме того, вам не нужен элемент EventArgs = e.

0 голосов
/ 13 мая 2009

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

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

0 голосов
/ 13 мая 2009

Пара быстрых мыслей:

Я бы сделал свойства доступными только для чтения, чтобы они соответствовали "нормальному" шаблону классов eventargs.

Возможно, свойства, относящиеся к информации об ошибках, должны быть объединены в некоторый класс ErrorInformation (это облегчит передачу этой информации другим методам).

Вопрос: для чего вы используете свойство EventArgs?

0 голосов
/ 13 мая 2009

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

В этом случае, если вы хотите иметь проверку, которая не будет генерировать исключения, тогда да, я бы добавил те поля, которые вам нужны, в ваши пользовательские аргументы событий - они уже являются пользовательскими, поэтому нет причин не расширять их чтобы удовлетворить ваши потребности: -)

Марк

...