Как сделать класс с определением и повышением событий в C#

В этом примере используется класс BankAccount для управления банковским счетом (и для определения способов и событий события). Если программа пытается удалить больше денег с учетной записи, чем ее текущий баланс, объект BankAccount вызывает событие Overdrawn. Событие включает в себя два параметра: объект с именем sender, который содержит ссылку на объект BankAccount, который поднимает событие, и объект OverdrawnArgs.

Объект OverdrawnArgs содержит два полезных свойства. Свойство DebitAmount указывает сумму, которую программа пытается удалить из учетной записи. Свойство Allow - это логическое значение, которое программа может установить в true, чтобы сообщить объекту BankAccount обработать дебет, даже если это даст учетную запись отрицательный баланс.

Программа должна выполнить пять основных шагов для определения и повышения событий.

Объект, который класс передает обработчику события, должен наследовать от EventArgs. Следующий код показывает класс OverdrawnArgs, используемый в этом примере.

// Используется для хранения информации, когда учетная запись перегружена.
class OverdrawnArgs : EventArgs
{
    // Сумма вычитается.
    public decimal DebitAmount;

    // Значение по умолчанию - не разрешать учетную запись
    // иметь отрицательный баланс.
    public bool Allow = false;
}

Этот класс предоставляет сумму дебетования, которая вызывает переопределение учетной записи. Поле Boolean Allow позволяет основной программе сообщать об этом объекту, разрешать ли ему дебет, даже если это даст отрицательный баланс учетной записи.

Обратите внимание, что класс OverdrawnArgs не включает текущий баланс учетной записи. Основная программа может получить это от самого объекта BankAccount. Он не мог получить сумму дебетов таким образом, поэтому он входит в класс OverdrawnArgs.

(Для бонусных очков вы можете сделать DebitAmount свойство только для чтения. Вы можете поместить его и BankAccount в сборку и использовать internal , чтобы класс BankAccount установил значение, но не позволял основной программе установить его. Или вы можете сделать конструктор установленным значением. Обычно программисты просто оставляют этот вид свойств read-write и затем игнорируйте любые изменения, внесенные программой.)

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

// Поднято, если программа пытается дебетовать больше
// чем баланс учетной записи.
public delegate void OverdrawnEventHandler(
    object sender, OverdrawnArgs args);
public event OverdrawnEventHandler Overdrawn

Этот код означает, что событие Overdrawn должно обрабатываться обработчиком событий, который принимает два параметра: объект с именем sender, представляющий объект, который поднял событие, и Объект OverdrawnArgs.

В качестве альтернативы вы можете использовать предопределенный тип делегата EventHandler, как показано в следующем коде.

public event EventHandler Overdrawn

Этот оператор примерно эквивалентен предыдущим двум операторам, которые сначала определили отдельный тип делегата.

Эта версия проще (и все дело в том, что Microsoft изобретает предопределенный тип EventHandler), так вот как это делает этот пример.

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

// Текущий баланс учетной записи.
public decimal Balance { get; set; }

// Вычитаем из учетной записи.
public void Debit(decimal amount)
{
    if (amount < 0) throw new
        ArgumentOutOfRangeException(
            "Debit amount must be positive.");

    // Посмотрите, держит ли эта сумма столько денег.
    if (Balance >= amount)
    {
        // Достаточно денег. Вычтите сумму.
        Balance -= amount;
    }
    else
    {
        // Недостаточно денег.
        // Вызов события Overdrawn.
        if (Overdrawn != null)
        {
            // Создаем объект OverdrawnArgs.
            OverdrawnArgs args = new OverdrawnArgs();
            args.DebitAmount = amount;

            // Поднять событие.
            Overdrawn(this, args);

            // Если программа хочет разрешить учетную запись
            // чтобы иметь отрицательный баланс, удалите деньги.
            if (args.Allow) Balance -= amount;
        }
    }
}

В поле Balance содержится текущий баланс учетной записи.

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

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

Если баланс недостаточен, метод вызывает событие Overdrawn. Оператор if (Overdrawn! = Null) проверяет, подписался ли какой-либо код на событие. Это странный синтаксис, но если для события не зарегистрировано обработчиков событий, то Overdrawn есть null, поэтому методу не нужно поднимать событие. На самом деле, если он пытается поднять событие, он получает исключение «Объектная ссылка, не установленная на экземпляр объекта».

Если обработчик события подписан на событие, метод создает объект OverdrawnArgs и устанавливает его DebitAmount. Затем он использует синтаксис Overdrawn (this, args), чтобы поднять событие, передав текущий объект и объект OverdrawnArgs подписанным обработчикам событий.

Когда обработчики событий возвращаются, метод проверяет значение OverdrawnArgs объекта Allow объекта, чтобы узнать, должен ли он дебетовать учетную запись в любом случае. Если Allow true, метод вычитает сумму дебетования из текущего баланса.

Если класс, который вы создаете, является компонентом или элементом управления, вы можете использовать отображение событий окна «Свойства» для создания обработчиков событий. В противном случае вам нужно подписаться на обработчики событий в коде.

Следующий код показывает, как основная программа инициализирует свой объект BankAccount и подписывается на событие Overdrawn этого объекта.

// Объект BankAccount, управляемый этой программой.
private BankAccount TheBankAccount;

// Инициализировать объект BankAccount.
private void Form1_Load(object sender, EventArgs e)
{
    TheBankAccount = new BankAccount();
    TheBankAccount.Balance = 100m;
    txtBalance.Text = TheBankAccount.Balance.ToString("C");

    // Подписываться на событие Overdrawn.
    TheBankAccount.Overdrawn += Account_Overdrawn;
}

Обработчик события Load формы создает объект BankAccount, дает баланс $ 100.00 и отображает текущий баланс.

Обработчик события Load формы создает объект BankAccount, дает баланс $ 100.00 и отображает текущий баланс.

...

Когда объект BankAccount вызывает событие Overdrawn, выполняется следующий обработчик событий Account_Overdrawn.

// Обрабатывать событие Overdrawn.
private void Account_Overdrawn(object sender, OverdrawnArgs e)
{
    // Получить учетную запись.
    BankAccount account = sender as BankAccount;

    // Попросите пользователя разрешить это.
    if (MessageBox.Show("Insufficient funds.\n\n    Current balance: " +
        account.Balance.ToString("C") + "\n    Debit amount: " +
        e.DebitAmount.ToString("C") + "\n\n" +
        "Do you want to allow this transaction anyway?",
        "Allow?", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
            == DialogResult.Yes)
    {
        // Разрешить транзакцию в любом случае.
        e.Allow = true;
    }
}

Этот метод преобразует параметр sender в объект BankAccount. (Это первый шаг во многих обработчиках событий. Очень плохо, что предопределенный тип делегата EventHandler не принимает двух параметров типа, поэтому вы можете сделать параметр sender иметь тип BankAccount вместо object. Тогда вы можете пропустить этот шаг. К сожалению, это не так, как определено EventHandler.)

Затем обработчик события отображает окно сообщения, в котором указывается информация о транзакции и спрашивается у пользователя, разрешить ли он транзакции. Если пользователь нажимает «Да», код устанавливает поле OverdrawnArgs объекта Allow в true, чтобы объект BankAccount, который поднял событие знает, что оно должно разрешить транзакцию.

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

Источник: http://csharphelper.com/blog/2017/11/make-a-class-define-and-raise-events-in-c/

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Adblock
detector