Вопрос

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

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

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

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

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

Вот мой класс 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) 

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

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

Спасибо, Макс

Это было полезно?

Решение

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

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

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;
}

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

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

Другие советы

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

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

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

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

Марк

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top