C# 이벤트 이해하기
C#에서 이벤트는 많은 개발자가 사용하는 기본적인 개념이지만, 특히 자신만의 이벤트를 생성하는 경우 완전히 이해하지 못하는 경우가 많습니다. Tim Corey는 그의 비디오 " C# 이벤트 - 애플리케이션에서 이벤트 생성 및 사용 "에서 이벤트를 생성하고 사용하는 방법에 대한 포괄적인 가이드를 제공하며, 모범 사례와 고급 기능을 살펴봅니다.
이 글에서는 C# 이벤트에 대해 자세히 살펴보겠습니다. 이벤트의 구문, 정의 방법, 그리고 Tim Corey의 비디오 예제를 통해 일반적인 프로그래밍 문제를 해결하는 데 어떻게 도움이 되는지 알아보겠습니다. C#에서 이벤트 처리를 이해하는 것은 반응형 애플리케이션을 구축하는 데 필수적이며, 이 글은 사용자 지정 오류 로깅, 예외 처리 및 이벤트 기반 프로그래밍의 핵심 개념을 파악하는 데 도움이 될 것입니다.
이벤트 소개
C#을 비롯한 프로그래밍 언어에서 이벤트는 이벤트 기반 프로그래밍에서 매우 중요한 역할을 하며, 애플리케이션이 사용자 상호 작용이나 시스템 변경과 같은 작업에 반응할 수 있도록 해줍니다. 다른 프로그래밍 언어와 비교했을 때, C#은 이벤트 처리에 구조화된 접근 방식을 제공하므로 빠르고 작은 애플리케이션에 이상적입니다. C#에서 이벤트는 특정 동작에 의해 발생하며, 이러한 동작은 원하는 작업을 수행하기 위해 해당 이벤트 핸들러를 호출합니다.
Tim은 대부분의 개발자가 C#의 이벤트에 익숙하지만 사용자 지정 이벤트를 만드는 방법은 모를 수 있다고 설명하며 이야기를 시작합니다. 이 비디오의 목표는 이벤트를 소개하고, 사용자 지정 이벤트를 만드는 과정을 안내하고, 이벤트의 기능을 설명하고, 모범 사례를 제시하는 것입니다.
데모 애플리케이션 사용법 안내
Tim은 Windows Forms(WinForms)로 제작된 간단한 은행 애플리케이션을 사용하여 이벤트를 시연합니다. 이 애플리케이션은 잔액 조회 및 거래 기록 등 한 고객에 대한 기본적인 은행 업무를 시뮬레이션합니다.
애플리케이션 개요 :
- 해당 애플리케이션에는 두 가지 양식이 있습니다. 하나는 계좌 잔액과 거래 내역을 표시하는 양식이고, 다른 하나는 새로운 거래를 기록하는 양식입니다.
- 신용카드 구매를 시뮬레이션하고, 예금 계좌에서 당좌 계좌로 자금을 이체하여 초과 인출을 처리하는 버튼이 포함되어 있습니다.
주요 양식 :
- 고객 이름과 당좌 예금 및 저축 예금 계좌 잔액을 표시합니다.
- 두 계정의 거래 내역 목록을 보여줍니다.
- 거래 기록 양식을 여는 버튼이 포함되어 있습니다.
거래 양식 :
- 사용자가 거래 금액을 입력할 수 있도록 합니다.
- 구매 과정을 시뮬레이션하고, 저축 계좌에서 당좌 계좌로 자금을 이체하여 초과 인출을 처리합니다.
데모 앱의 코드
팀은 데모 뱅킹 애플리케이션의 백엔드 코드를 설명합니다.
고객 등급 :
- 고객 명의의 자산과 두 개의 계좌(당좌예금 및 저축예금)를 나타냅니다.
- Customer 클래스는 간단하지만 여러 계정을 관리하는 방법을 이해하는 데 좋은 출발점이 됩니다.
계정 분류 :
- 계좌명, 잔액, 거래 내역 등 은행 계좌의 세부 정보를 관리합니다.
- 잔액 속성은 정확한 금액 계산을 위해 소수점 형식입니다.
- Transactions 속성은 외부 수정을 방지하기 위해 읽기 전용 목록입니다.
예치금 및 결제 처리 :
- AddDeposit 메서드 : 계좌에 입금을 추가하고, 잔액을 업데이트하며, 거래를 기록합니다.
- 결제 방식 : 출금을 처리하며, 잔액 확인 및 필요한 경우 백업 계좌에서 자금을 이체하여 초과 인출 방지 기능을 관리합니다.
초과인출 보호 :
- 해당 애플리케이션에는 초과 인출을 처리하는 로직이 포함되어 있습니다. 당좌 예금 계좌 잔액이 거래에 필요한 금액보다 부족할 경우, 애플리케이션은 부족분을 충당하기 위해 저축 예금 계좌를 확인합니다. 합산 잔액이 충분하면 필요한 금액을 당좌 예금 계좌로 이체하여 거래를 완료합니다.
코드 예시는 팀 코리의 영상에서 3분 18초부터 18분 27초까지 코드를 설명하는 부분을 직접 참고하시면 됩니다.
이벤트: 버튼 클릭
이 섹션에서 Tim Corey는 Windows Forms의 버튼 클릭 이벤트 작동 방식을 자세히 살펴보고 이러한 이벤트가 어떻게 연결되고 어떻게 작동하는지 설명했습니다.
버튼 클릭 이벤트 이해하기
팀은 윈도우 폼 애플리케이션에서 흔히 볼 수 있는 버튼 클릭 이벤트 개념을 설명하는 것으로 이야기를 시작합니다. 디자이너에서 버튼을 두 번 클릭하면 Visual Studio는 클릭 이벤트에 대한 이벤트 처리기 메서드를 자동으로 생성합니다.
이벤트 핸들러 메서드 :
- 이 메서드는 버튼을 클릭할 때마다 호출됩니다. 버튼 클릭에 대한 응답으로 실행될 코드를 배치하는 곳입니다.
private void recordTransactionButton_Click(object sender, EventArgs e) { // Code to handle the button click event }private void recordTransactionButton_Click(object sender, EventArgs e) { // Code to handle the button click event }이벤트 준비 :
- 이벤트 핸들러 메서드는 폼 디자인 파일(FormName.Designer.cs)의 버튼 클릭 이벤트에 연결되어 있습니다. 이는 '+=' 연산자를 사용하여 버튼의 클릭 이벤트에 이벤트 핸들러를 추가하는 방식으로 이루어집니다.
this.recordTransactionButton.Click += new System.EventHandler(this.recordTransactionButton_Click);this.recordTransactionButton.Click += new System.EventHandler(this.recordTransactionButton_Click);
사용자 지정 이벤트 생성 및 호출
Tim은 C#에서 사용자 지정 이벤트를 만드는 방법을 설명하며, 이벤트가 트리거될 Account 클래스부터 시작합니다.
이벤트 정의하기 :
- 이벤트는 event 키워드를 사용하여 정의됩니다. 공개 변수와 비슷해 보이지만, 이벤트 전용 변수입니다.
public event EventHandler<string> RaiseTransactionApprovedEvent;public event EventHandler<string> RaiseTransactionApprovedEvent;이벤트 발생시키기 :
- 이벤트는 일반적으로 이벤트를 정의하는 클래스 내의 Invoke 메서드를 사용하여 트리거됩니다. Invoke 메서드는 두 개의 매개변수를 받습니다: 발신자(보통은
this)와 이벤트 데이터(이 경우, 문자열)입니다.
private void OnTransactionApproved(string transactionName) { RaiseTransactionApprovedEvent?.Invoke(this, transactionName); }private void OnTransactionApproved(string transactionName) { RaiseTransactionApprovedEvent?.Invoke(this, transactionName); }- 이벤트는 일반적으로 이벤트를 정의하는 클래스 내의 Invoke 메서드를 사용하여 트리거됩니다. Invoke 메서드는 두 개의 매개변수를 받습니다: 발신자(보통은
연결 및 이벤트 처리 :
- '+=' 연산자를 사용하여 이벤트를 구독하고, 이벤트가 발생했을 때 이벤트를 처리하는 메서드를 정의합니다.
account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent; private void Account_RaiseTransactionApprovedEvent(object sender, string e) { // Code to handle the event }account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent; private void Account_RaiseTransactionApprovedEvent(object sender, string e) { // Code to handle the event }
이벤트를 사용하여 UI 업데이트하기
팀은 거래 승인과 같은 특정 작업이 발생할 때 브라우저 UI를 자동으로 업데이트하기 위해 이벤트를 사용하는 방법을 설명합니다.
모금 행사 :
- 거래가 승인된 후 사용자 지정 이벤트를 발생시킵니다.
public void AddDeposit(decimal amount, string depositName) { // Code to add deposit RaiseTransactionApprovedEvent?.Invoke(this, depositName); }public void AddDeposit(decimal amount, string depositName) { // Code to add deposit RaiseTransactionApprovedEvent?.Invoke(this, depositName); }사용자 인터페이스에서 이벤트 구독하기 :
- 메인 양식에서 해당 이벤트를 구독하면 새로운 거래가 승인될 때마다 거래 목록이 업데이트됩니다.
public MainForm() { InitializeComponent(); account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent; } private void Account_RaiseTransactionApprovedEvent(object sender, string e) { // Update the UI with the new transaction }public MainForm() { InitializeComponent(); account.RaiseTransactionApprovedEvent += Account_RaiseTransactionApprovedEvent; } private void Account_RaiseTransactionApprovedEvent(object sender, string e) { // Update the UI with the new transaction }
Event?.Invoke() 설명
Tim Corey는 C#에서 이벤트를 발생시킬 때 ?.Invoke() 구문을 사용하는 방법을 설명합니다. 이러한 최신 접근 방식은 코드를 단순화하고 스레드 안전성을 보장합니다.
물음표 연산자
Invoke 앞에 있는 물음표(?)는 null 조건부 연산자입니다. 이벤트 핸들러를 호출하기 전에 해당 핸들러가 null인지 확인하여 잠재적인 예외 발생을 방지합니다.
전통적인 접근 방식 :
- 이전에는 개발자들이 이벤트 핸들러가 null인지 확인한 후 호출하기 위해 여러 줄의 코드를 사용했습니다.
if (RaiseTransactionApprovedEvent != null) { RaiseTransactionApprovedEvent(this, depositName); }if (RaiseTransactionApprovedEvent != null) { RaiseTransactionApprovedEvent(this, depositName); }?.Invoke() 를 사용한 최신 접근 방식 :
- 널 조건 연산자는 널 검사와 이벤트 호출을 한 줄로 수행하여 이 프로세스를 간소화합니다.
RaiseTransactionApprovedEvent?.Invoke(this, depositName);RaiseTransactionApprovedEvent?.Invoke(this, depositName);RaiseTransactionApprovedEvent이(가) null인 경우, 호출이 진행되지 않아 어떤 예외도 피할 수 있습니다.
장점 :
- 코드 간소화 : 이벤트를 안전하게 호출하는 데 필요한 코드 양을 줄입니다.
- 스레드 안전성 : null 값을 확인하고 이벤트를 한 번에 호출함으로써 경쟁 조건을 제거합니다.
이벤트에 맞춰 코드를 작성하고 듣기
Tim은 Windows Forms 애플리케이션에서 사용자 지정 이벤트를 수신하고 그에 따라 UI를 업데이트하는 방법을 설명합니다.
이벤트 구독하기 :
- += 연산자를 사용하여 사용자 지정 이벤트를 구독하세요.
customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent;이벤트 핸들러 메서드 :
- 이벤트를 처리하는 메서드를 정의하십시오. 이 메서드는 이벤트 데이터를 기반으로 UI를 업데이트합니다.
private void CheckingAccount_TransactionApprovedEvent(object sender, string e) { // Update the UI with the new transaction checkingTransactionsDataSource.DataSource = null; checkingTransactionsDataSource.DataSource = customer.CheckingAccount.Transactions; checkingBalanceLabel.Text = customer.CheckingAccount.Balance.ToString("C2"); }private void CheckingAccount_TransactionApprovedEvent(object sender, string e) { // Update the UI with the new transaction checkingTransactionsDataSource.DataSource = null; checkingTransactionsDataSource.DataSource = customer.CheckingAccount.Transactions; checkingBalanceLabel.Text = customer.CheckingAccount.Balance.ToString("C2"); }
사용자 지정 이벤트 만들기: 이벤트 실행 과정 및 요약
팀은 사용자 지정 이벤트를 생성, 발생 및 처리하는 전체 과정을 실제로 시연합니다.
이벤트 발생시키기 :
- 거래가 승인되거나 잔액이 변경될 때 이벤트를 발생시키세요.
private void OnTransactionApproved(string transactionName) { RaiseTransactionApprovedEvent?.Invoke(this, transactionName); }private void OnTransactionApproved(string transactionName) { RaiseTransactionApprovedEvent?.Invoke(this, transactionName); }여러 이벤트 처리 :
- 애플리케이션이 거래 및 잔액 변동과 같은 여러 이벤트를 수신하여 사용자 인터페이스를 실시간으로 업데이트할 수 있도록 하십시오.
public MainForm() { InitializeComponent(); customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent; customer.SavingsAccount.TransactionApprovedEvent += SavingsAccount_TransactionApprovedEvent; } private void SavingsAccount_TransactionApprovedEvent(object sender, string e) { // Update the UI with the new savings transaction savingsTransactionsDataSource.DataSource = null; savingsTransactionsDataSource.DataSource = customer.SavingsAccount.Transactions; savingsBalanceLabel.Text = customer.SavingsAccount.Balance.ToString("C2"); }public MainForm() { InitializeComponent(); customer.CheckingAccount.TransactionApprovedEvent += CheckingAccount_TransactionApprovedEvent; customer.SavingsAccount.TransactionApprovedEvent += SavingsAccount_TransactionApprovedEvent; } private void SavingsAccount_TransactionApprovedEvent(object sender, string e) { // Update the UI with the new savings transaction savingsTransactionsDataSource.DataSource = null; savingsTransactionsDataSource.DataSource = customer.SavingsAccount.Transactions; savingsBalanceLabel.Text = customer.SavingsAccount.Balance.ToString("C2"); }애플리케이션 실행 :
- 팀은 애플리케이션을 실행하여 트랜잭션으로 인해 발생하는 이벤트에 따라 사용자 인터페이스가 자동으로 업데이트되는 방식을 시연합니다.
이벤트 인자 정보: 디버깅
팀은 이벤트 디버깅 방법과 이벤트와 함께 전송되는 정보를 검사하는 방법을 보여줍니다.
중단점 설정 :
- 이벤트 처리기 메서드에 중단점을 설정하여 이벤트 데이터를 검사하십시오.
private void CheckingAccount_TransactionApprovedEvent(object sender, string e) { // Breakpoint here }private void CheckingAccount_TransactionApprovedEvent(object sender, string e) { // Breakpoint here }디버깅 :
- 애플리케이션을 실행하고 트랜잭션을 수행하여 이벤트를 발생시키십시오. 디버거에서 이벤트 인수를 검사하십시오.
- sender 매개변수는 이벤트를 발생시킨 인스턴스를 제공하고, e 매개변수는 이벤트 데이터를 포함합니다.
사용자 지정 이벤트(초과 인출 이벤트)를 하나 더 생성하기
팀 코리는 초과 인출 상황을 처리하는 또 다른 사용자 지정 이벤트를 만들어 데모를 확장했습니다. 이 이벤트는 잔액 부족이 발생했을 때 발생하며, 사용자에게 잔액 부족 금액을 알려줍니다.
초과인출 사유 정의
Tim은 먼저 Account 클래스에 초과 인출 상황에 대한 새로운 이벤트를 정의합니다.
이벤트 선언 :
- 초과 인출 금액을 전달하기 위해 소수점 형식으로 event 키워드를 사용하여 이벤트를 정의하십시오.
public event EventHandler<decimal> OverdraftEvent;public event EventHandler<decimal> OverdraftEvent;이벤트 발생시키기 :
- 해당 이벤트는 초과 인출이 성공적으로 발생하는 코드 부분에서 트리거됩니다.
if (overdraftSuccessful) { OverdraftEvent?.Invoke(this, overdraftAmount); }if (overdraftSuccessful) { OverdraftEvent?.Invoke(this, overdraftAmount); }
대시보드에서 초과인출 이벤트 구독하기
이벤트 준비 :
- 대시보드 양식에서 초과인출 이벤트에 대한 구독을 신청하세요.
customer.CheckingAccount.OverdraftEvent += CheckingAccount_OverdraftEvent;customer.CheckingAccount.OverdraftEvent += CheckingAccount_OverdraftEvent;이벤트 처리 :
- 잔액 부족이 발생했을 때 메시지를 표시하는 이벤트 핸들러를 정의하십시오.
private void CheckingAccount_OverdraftEvent(object sender, decimal e) { errorMessage.Text = $"You had an overdraft protection transfer of {e:C2}"; errorMessage.Visible = true; }private void CheckingAccount_OverdraftEvent(object sender, decimal e) { errorMessage.Text = $"You had an overdraft protection transfer of {e:C2}"; errorMessage.Visible = true; }이벤트 발생 및 표시 :
- 잔액 부족이 발생하면 이벤트가 발생하고 사용자 인터페이스가 업데이트되어 사용자에게 알립니다.
You had an overdraft protection transfer of $20.44
여러 장소에서 발생하는 사건을 청취하기
팀은 동일한 이벤트를 여러 언어와 형식으로 듣는 방법을 설명하며 이벤트의 다양성을 보여줍니다.
다른 양식에 레이블 추가하기 :
- 보조 양식에 레이블을 추가하여 초과 인출 메시지를 표시합니다.
<asp:Label ID="errorMessage" runat="server" Visible="false" /><asp:Label ID="errorMessage" runat="server" Visible="false" />HTML이벤트 참가 신청 :
- 보조 양식에서 초과 인출 이벤트를 구독하세요.
customer.CheckingAccount.OverdraftEvent += SecondaryForm_OverdraftEvent;customer.CheckingAccount.OverdraftEvent += SecondaryForm_OverdraftEvent;이벤트 처리 :
- 보조 양식에 초과 인출 메시지를 표시하는 이벤트 핸들러를 정의합니다.
private void SecondaryForm_OverdraftEvent(object sender, decimal e) { errorMessage.Visible = true; }private void SecondaryForm_OverdraftEvent(object sender, decimal e) { errorMessage.Visible = true; }동시 이벤트 처리 :
- Tim은 해당 이벤트가 여러 형태로 동시에 처리될 수 있음을 보여줌으로써 애플리케이션의 모든 관련 부분이 이벤트에 적절하게 대응하도록 보장합니다.
Both the main form and the secondary form display the overdraft message when the event is triggered.
이벤트 리스너를 메모리에서 제거하기
Tim은 메모리 누수를 방지하고 애플리케이션 성능을 제대로 유지하기 위해 이벤트 리스너를 정리하는 것이 중요하다고 강조합니다.
이벤트 구독 취소 :
클래스 인스턴스를 소멸시키거나 폼을 닫기 전에 이벤트 구독을 해제하는 것이 매우 중요합니다.
customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;왜 중요한가 :
- 이벤트 구독을 해제하지 않으면 이벤트를 수신하는 객체가 제대로 가비지 컬렉션되지 않아 메모리 누수가 발생할 수 있습니다.
명명된 메서드 사용 :
- 이벤트 핸들러에 익명 함수를 사용하지 마십시오. 익명 함수를 사용하면 이벤트 구독을 취소하기가 어려워집니다.
// Good practice: using named methods for event handlers// Good practice: using named methods for event handlers
일반 이벤트 핸들러: T에 클래스 전달하기
팀 코리는 이벤트를 통해 데이터를 전달하는 최적의 방법, 특히 문자열이나 소수점과 같은 단순 데이터 유형 대신 클래스를 사용하는 이점에 대해 설명합니다.
이벤트 데이터에 클래스를 사용하는 이유는 무엇일까요?
팀은 이벤트에 단순 데이터 타입을 사용하는 것이 일반적이지 않은 이유와 클래스를 전달하는 것이 일반적으로 더 나은 이유에 대해 논의하는 것으로 이야기를 시작합니다.
유연성 및 확장성 :
클래스를 사용하면 여러 관련 데이터를 이벤트로 전달할 수 있습니다. 나중에 데이터를 더 추가해야 하는 경우 이벤트 시그니처를 변경하지 않고 클래스를 확장하기만 하면 됩니다.
EventArgs 상속 :
- 이전에는 이벤트를 통해 전달되는 모든 객체가 EventArgs를 상속해야 했지만, 더 이상 그럴 필요가 없습니다. 하지만 EventArgs를 상속받는 것은 일관성과 명확성을 위해 여전히 도움이 될 수 있습니다.
초과인출 이벤트 인수 클래스 생성
Tim은 잔액 부족 이벤트에 대한 사용자 지정 EventArgs 클래스를 만드는 방법을 보여줍니다.
클래스를 정의합니다 .
- EventArgs를 상속받고 이벤트에 전달할 데이터에 대한 속성을 포함하는 새 클래스를 만드세요.
public class OverdraftEventArgs : EventArgs { public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; } public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo) { AmountOverdrafted = amountOverdrafted; MoreInfo = moreInfo; } }public class OverdraftEventArgs : EventArgs { public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; } public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo) { AmountOverdrafted = amountOverdrafted; MoreInfo = moreInfo; } }이벤트에서 클래스 사용하기 :
- 사용자 지정 EventArgs 클래스를 사용하도록 이벤트 선언을 업데이트하십시오.
public event EventHandler<OverdraftEventArgs> OverdraftEvent;public event EventHandler<OverdraftEventArgs> OverdraftEvent;이벤트 발생시키기 :
- 이벤트를 호출할 때 사용자 지정 EventArgs 클래스의 인스턴스를 전달합니다.
OverdraftEvent?.Invoke(this, new OverdraftEventArgs(amountNeeded, "Additional info"));OverdraftEvent?.Invoke(this, new OverdraftEventArgs(amountNeeded, "Additional info"));
읽기 전용 속성의 중요성
Tim은 이벤트 데이터가 실수로 수정되는 것을 방지하기 위해 EventArgs 클래스에서 읽기 전용 속성을 사용하는 것이 중요하다고 강조합니다.
수정 방지 :
- EventArgs 클래스의 속성에 public setter가 있는 경우, 모든 이벤트 핸들러가 데이터를 수정할 수 있으므로 예기치 않은 동작이 발생할 수 있습니다.
- private setter를 사용하고 생성자를 통해 속성을 초기화하면 이벤트 데이터의 일관성이 유지됩니다.
문제 예시 :
- Tim은 속성이 읽기 전용이 아닌 경우 한 이벤트 핸들러에서 이벤트 데이터를 수정하면 다른 핸들러에 어떤 영향을 미칠 수 있는지 보여줍니다.
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { e.AmountOverdrafted = 1000; // This modification affects all handlers }private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { e.AmountOverdrafted = 1000; // This modification affects all handlers }해결책 :
- 속성을 읽기 전용으로 만들려면 private setter를 사용하고 생성자를 통해 데이터를 전달하세요.
public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; }public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; }
공개 집합을 사용해야 하는 예외 상황(59:29)
Tim Corey는 이벤트 데이터 속성에 대해 비공개 setter를 사용하는 규칙에 대한 중요한 예외 사항을 강조합니다. 이 예외는 특정 조건에 따라 거래가 취소될 수 있는 경우와 같이 이벤트 리스너가 이벤트 데이터를 수정할 수 있도록 허용해야 하는 경우에 발생합니다.
예시: 거래 취소
Tim은 이벤트 핸들러가 트랜잭션을 취소해야 할 수 있는 예를 제시합니다. 이는 사용자 지정 EventArgs 클래스에 CancelTransaction 속성을 추가함으로써 구현됩니다.
속성 정의 :
- EventArgs 클래스에 getter와 setter를 모두 포함하는 public 속성을 추가합니다.
public class OverdraftEventArgs : EventArgs { public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; } public bool CancelTransaction { get; set; } = false; public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo) { AmountOverdrafted = amountOverdrafted; MoreInfo = moreInfo; } }public class OverdraftEventArgs : EventArgs { public decimal AmountOverdrafted { get; private set; } public string MoreInfo { get; private set; } public bool CancelTransaction { get; set; } = false; public OverdraftEventArgs(decimal amountOverdrafted, string moreInfo) { AmountOverdrafted = amountOverdrafted; MoreInfo = moreInfo; } }이벤트 핸들러에서 속성 설정하기 :
- 대시보드에서 이벤트 핸들러는 이 속성을 설정하여 거래를 취소할 수 있습니다.
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { if (denyOverdraft.Checked) { e.CancelTransaction = true; } errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}"; errorMessage.Visible = true; }private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { if (denyOverdraft.Checked) { e.CancelTransaction = true; } errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}"; errorMessage.Visible = true; }소스 메서드에서 속성 확인하기 :
- 이벤트를 발생시키는 메서드에서, 진행하기 전에 CancelTransaction 속성이 true로 설정되어 있는지 확인하십시오.
if (args.CancelTransaction) { return false; // Transaction is canceled }if (args.CancelTransaction) { return false; // Transaction is canceled }
애플리케이션을 더욱 상호작용적으로 만들기
팀은 애플리케이션을 더욱 개선하여 상호작용적이고 사용자 친화적으로 만듭니다.
초과인출 관리용 체크박스 추가 :
- 사용자가 초과인출 방지 기능을 활성화 또는 비활성화할 수 있도록 양식에 체크박스를 추가하세요.
private void InitializeComponent() { this.denyOverdraft = new System.Windows.Forms.CheckBox(); // Initialize other controls this.denyOverdraft.Text = "Stop Overdrafts"; this.denyOverdraft.CheckedChanged += new System.EventHandler(this.denyOverdraft_CheckedChanged); }private void InitializeComponent() { this.denyOverdraft = new System.Windows.Forms.CheckBox(); // Initialize other controls this.denyOverdraft.Text = "Stop Overdrafts"; this.denyOverdraft.CheckedChanged += new System.EventHandler(this.denyOverdraft_CheckedChanged); }체크박스 상태 처리 :
- 체크박스 이벤트 핸들러에서 거래 취소 여부를 결정할 때 체크박스 상태를 고려하도록 로직을 업데이트하세요.
private void denyOverdraft_CheckedChanged(object sender, EventArgs e) { if (denyOverdraft.Checked) { // Logic to stop overdraft transactions } }private void denyOverdraft_CheckedChanged(object sender, EventArgs e) { if (denyOverdraft.Checked) { // Logic to stop overdraft transactions } }이벤트 핸들러 업데이트 :
- 이벤트 처리기가 초과 인출 허용 또는 거부 여부를 결정하는 체크박스 상태를 준수하는지 확인하십시오.
private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { if (denyOverdraft.Checked) { e.CancelTransaction = true; } errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}"; errorMessage.Visible = true; }private void CheckingAccount_OverdraftEvent(object sender, OverdraftEventArgs e) { if (denyOverdraft.Checked) { e.CancelTransaction = true; } errorMessage.Text = $"You had an overdraft protection transfer of {e.AmountOverdrafted:C2}"; errorMessage.Visible = true; }
요약
팀 코리는 C#에서 이벤트를 다룰 때의 핵심 사항과 모범 사례를 요약하며 튜토리얼을 마무리합니다.
이벤트 리스너 제거 :
- 메모리 누수를 방지하기 위해 객체를 파괴하기 전에 항상 이벤트 리스너를 제거하십시오.
- 이벤트 구독을 취소하려면 -= 연산자를 사용하십시오.
customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;customer.CheckingAccount.OverdraftEvent -= CheckingAccount_OverdraftEvent;EventArgs 상속 사용 :
- 필수 사항은 아니지만, EventArgs를 상속하면 일관성을 유지하고 EventArgs.Empty와 같은 내장 기능을 사용하는 데 도움이 될 수 있습니다.
읽기 전용 속성에 대한 비공개 설정자 :
- 의도치 않은 이벤트 데이터 변경을 방지하려면 비공개 설정자를 사용하십시오. 취소 가능한 거래와 같이 필요한 경우에만 공개 설정자를 허용하십시오.
- 이벤트 핸들러 구문 :
- EventHandler 대리자를 사용하여 이벤트를 정의하고, 이벤트 데이터를 전달하는 명확하고 일관된 패턴을 제공합니다.
널 조건 연산자 :
- null 조건 연산자(?.Invoke())를 사용하면 null 참조 예외 발생 위험 없이 안전하게 이벤트를 호출할 수 있습니다.
결론
Tim Corey의 C# 이벤트 에 대한 종합적인 튜토리얼은 이벤트를 효과적으로 생성, 처리 및 관리하는 데 유용한 통찰력과 실용적인 예제를 제공합니다. 이러한 모범 사례를 따르면 개발자는 더욱 상호작용적이고 반응성이 뛰어난 애플리케이션을 만들 수 있습니다.

