델리게이트를 사용하여 “event”키워드를 사용하지 않고 동일한 작업을 수행 할 수 있는데 이벤트를 정의하는 동안 “event”키워드가 필요한 이유를 이해할 수 없습니다.
예 :
public delegate void CustomEventHandler(int a, string b);
public event CustomEventHandler customEvent;
customEvent += new CustomEventHandler(customEventHandler);
customEvent(1,"a"); // Raising the event
여기서 두 번째 줄에서 “event”키워드를 제거하면 델리게이트를 호출하여 이벤트를 발생시킬 수도 있습니다. 아무도이 이벤트 키워드가 필요한 이유를 말해 줄 수 있습니까?
답변
이 필드를-같은 이벤트 위임 유형의 공공 분야 보면 비슷하지만 실제로는 매우 다릅니다.
이벤트는 기본적으로 속성과 비슷합니다. 속성의 get / set 대신에 추가 / 제거 메서드 쌍입니다. 필드와 같은 이벤트 (예 : 직접 추가 / 제거 비트를 지정하지 않은 이벤트)를 선언하면 공개 이벤트가 생성되고 비공개 지원 필드가 생성됩니다. 이렇게하면 이벤트를 비공개로 제기 할 수 있지만 공개 구독은 허용됩니다. 공개 델리게이트 필드를 사용하면 누구나 다른 사람의 이벤트 처리기를 제거하고 이벤트를 직접 발생시키는 등의 작업을 수행 할 수 있습니다. 이는 캡슐화 재앙입니다.
이벤트 (및 대리인)에 대한 자세한 내용은이 주제에 대한 내 기사를 읽어보십시오 . (언젠가는 필드와 같은 이벤트를 매우 약간 변경하는 C # 4에 대해 이것을 업데이트해야합니다. 요점은 여전히 옳습니다.)
답변
이벤트 키워드는 다음 세 가지 작업을 수행합니다.
- 인터페이스에서 일반 필드를 정의 할 수 없더라도 인터페이스에서 이벤트를 정의 할 수 있습니다.
=
및()
연산자 (할당 및 호출) 의 가시성 을 private으로 변경하여 포함하는 클래스 만 이벤트를 호출하거나 이벤트에 포함 된 모든 메서드를 재정의 할 수 있습니다.-=
및+=
연산자는 여전히 외부에서 이벤트에 클래스 (그들은 액세스 수정은 다음 이벤트에 쓴 얻을)을 정의를 호출 할 수 있습니다.- 당신은 또한 방법을 대체 할 수 있습니다
-=
및+=
이벤트에 동작합니다.
답변
다른 대답은 괜찮습니다. 다른 생각을 추가하고 싶습니다.
귀하의 질문은 “대리자 유형의 필드가있을 때 이벤트가 필요한 이유는 무엇입니까?”입니다. 나는 그 질문을 확장 할 것입니다. 대리자 형식의 필드가있는 경우 메서드, 속성, 이벤트, 인스턴스 생성자 또는 종료자가 필요한 이유는 무엇입니까? 형식에 값과 대리자를 포함하는 필드 외에 다른 것이 필요한 이유는 무엇 입니까? 그냥 말하지 않는 이유
class C
{
private int z;
public readonly Func<int, int> M = (int x)=>{ return x+z; }
// ... and so on
}
?
메서드, 속성 또는 이벤트 가 필요 하지 않습니다 . 방법, 속성 및 이벤트 디자인 패턴이 중요하고 유용하며 언어로 구현할 수있는 표준적이고 문서화 된 명확한 방법을 가질 자격이 있기 때문에 우리는 그러한 것들을 제공합니다.
답변
event
키워드 를 생략하면 캡슐화가 깨지기 때문에 부분적으로 필요합니다 . 공용 멀티 캐스트 델리게이트 인 경우 누구나 호출하거나 null로 설정하거나 조작 할 수 있습니다. 호출 된 클래스 MailNotifier
가 있고 호출 된 이벤트가있는 경우 MailReceived
다른 유형이 호출을 통해 해당 이벤트를 발생시킬 수 있다는 것은 의미가 없습니다 mailNotifier.MailReceived()
.
반면에, 당신은 그것을 정의한 유형의 ‘field like’이벤트에만 개입하고 호출 할 수 있습니다.
이벤트 호출을 비공개로 유지하려는 경우 다음과 같은 작업을 중단 할 수 없습니다.
public class MyClassWithNonFieldLikeEvent
{
private CustomEventHandler m_delegate;
public void Subscribe(CustomEventHandler handler)
{
m_delegate += handler;
}
public void Unsubscribe(CustomEventHandler handler)
{
m_delegate -= handler;
}
private void DoSomethingThatRaisesEvent()
{
m_delegate.Invoke(...);
}
}
…하지만 그것은 필드와 같은 이벤트가 이미 우리에게 제공하는 것을 (더 많든 적든) 수행하기위한 전체 코드입니다.
답변
이벤트는 델리게이트 필드에 비해 뚜렷한 장점이 있습니다. 이벤트는 필드와 대조적으로 인터페이스에서 정의 할 수 있으며 코드에 추상화를 추가 할 수 있으며 더 중요한 것은 이벤트를 정의하는 클래스 내부에서만 호출 할 수 있다는 것입니다. 귀하의 경우 누구나 이벤트를 호출하여 코드를 파괴 할 수 있습니다.
자세한 내용은 이 블로그 게시물 을 참조하십시오 .
답변
대리자 는 참조 유형입니다. MulticastDelegate를 상속 합니다. 이벤트 는 수정 자입니다. 행사델리게이트에 대한 특수 수정 자입니다. 예를 들어 Invoke 메서드와 같은 일부 기능 / 메서드 접근성을 수정합니다. 수정 자 이벤트에 의해 수정 된 후 델리게이트 인스턴스는 새로운 개념 “이벤트”가됩니다. 따라서 이벤트는 하나의 수정 된 대리자 일뿐입니다. 참조를 직접 변경하거나 이벤트가 정의 된 클래스 외부에서 이벤트를 호출 할 수 없지만 참조를 변경하거나 일반 델리게이트 인스턴스를 호출 할 수 있습니다. 이벤트는 추가 보호 기능을 제공하여 이벤트에 더 많은 안전 기능을 제공합니다. 이벤트가 정의 된 클래스 외부에있을 때 이벤트 “+ =”및 “-=”에 대해 두 가지 작업을 수행 할 수 있습니다. 그러나 일반 대리자 인스턴스의 모든 공용 필드, 속성, 메서드 등에 액세스 할 수 있습니다. 다음은 한 가지 예입니다.
namespace DelegateEvent
{
//the following line behave as a class. It is indeed a reference type
public delegate void MyDelegate(string inputs);
//The following line is illegal. It can only be an instance. so it cannot be directly under namespace
//public event MyDelegate MyEvent;
public class MyClassA
{
public event MyDelegate MyEventA;
public MyDelegate MyDelegateA;
System.Threading.ManualResetEvent MyResetEvent = new System.Threading.ManualResetEvent(false);
public void TryToDoSomethingOnMyDelegateA()
{
if (MyDelegateA != null)
{
//User can assecc all the public methods.
MyDelegateA("I can invoke detegate in classA"); //invoke delegate
MyDelegateA.Invoke("I can invoke detegate in classA"); //invoke delegate
IAsyncResult result = MyDelegateA.BeginInvoke("I can invoke detegate in classA", MyAsyncCallback, MyResetEvent); //Async invoke
//user can check the public properties and fields of delegate instance
System.Reflection.MethodInfo delegateAMethodInfo = MyDelegateA.Method;
MyDelegateA = testMethod; //reset reference
MyDelegateA = new MyDelegate(testMethod); //reset reference
MyDelegateA = null; //reset reference
MyDelegateA += testMethod; //Add delegate
MyDelegateA += new MyDelegate(testMethod); //Add delegate
MyDelegateA -= testMethod; //Remove delegate
MyDelegateA -= new MyDelegate(testMethod); //Remove delegate
}
}
public void TryToDoSomethingOnMyEventA()
{
if (MyEventA != null)
{
MyEventA("I can invoke Event in classA"); //invoke Event
MyEventA.Invoke("I can invoke Event in classA"); //invoke Event
IAsyncResult result = MyEventA.BeginInvoke("I can invoke Event in classA", MyAsyncCallback, MyResetEvent); //Async invoke
//user can check the public properties and fields of MyEventA
System.Reflection.MethodInfo delegateAMethodInfo = MyEventA.Method;
MyEventA = testMethod; //reset reference
MyEventA = new MyDelegate(testMethod); //reset reference
MyEventA = null; //reset reference
MyEventA += testMethod; //Add delegate
MyEventA += new MyDelegate(testMethod); //Add delegate
MyEventA -= testMethod; //Remove delegate
MyEventA -= new MyDelegate(testMethod); //Remove delegate
}
}
private void MyAsyncCallback(System.IAsyncResult result)
{
//user may do something here
}
private void testMethod(string inputs)
{
//do something
}
}
public class MyClassB
{
public MyClassB()
{
classA = new MyClassA();
}
public MyClassA classA;
public string ReturnTheSameString(string inputString)
{
return inputString;
}
public void TryToDoSomethingOnMyDelegateA()
{
if (classA.MyDelegateA != null)
{
//The following two lines do the same job --> invoke the delegate instance
classA.MyDelegateA("I can invoke delegate which defined in class A in ClassB");
classA.MyDelegateA.Invoke("I can invoke delegate which defined in class A in ClassB");
//Async invoke is also allowed
//user can check the public properties and fields of delegate instance
System.Reflection.MethodInfo delegateAMethodInfo = classA.MyDelegateA.Method;
classA.MyDelegateA = testMethod; //reset reference
classA.MyDelegateA = new MyDelegate(testMethod); //reset reference
classA.MyDelegateA = null; //reset reference
classA.MyDelegateA += testMethod; //Add delegate
classA.MyDelegateA += new MyDelegate(testMethod); //Add delegate
classA.MyDelegateA -= testMethod; //Remove delegate
classA.MyDelegateA -= new MyDelegate(testMethod); //Remove delegate
}
}
public void TryToDoSomeThingMyEventA()
{
//check whether classA.MyEventA is null or not is not allowed
//Invoke classA.MyEventA is not allowed
//Check properties and fields of classA.MyEventA is not allowed
//reset classA.MyEventA reference is not allowed
classA.MyEventA += testMethod; //Add delegate
classA.MyEventA += new MyDelegate(testMethod); //Add delegate
classA.MyEventA -= testMethod; //Remove delegate
classA.MyEventA -= new MyDelegate(testMethod); //Remove delegate
}
private void testMethod(string inputs)
{
//do something here
}
}
}