문제

특히 사용자 인터페이스를 만드는 맥락에서 이벤트의 목적을 이해합니다. 나는 이것이 이벤트를 만드는 프로토 타입이라고 생각합니다.

public void EventName(object sender, EventArgs e);

이벤트 핸들러는 무엇을하고, 왜 필요한가, 그리고 어떻게 만들려면 어떻게해야합니까?

도움이 되었습니까?

해결책

이벤트 처리기를 이해하려면 이해해야합니다 대표. ~ 안에 씨#, 대의원을 메소드에 대한 포인터 (또는 참조)로 생각할 수 있습니다. 이것은 포인터를 값으로 전달할 수 있기 때문에 유용합니다.

대의원의 중심 개념은 서명 또는 모양입니다. 즉, (1) 리턴 유형 및 (2) 입력 인수입니다. 예를 들어, 대의원을 만드는 경우 void MyDelegate(object sender, EventArgs e), 반환 방법 만 가리킬 수 있습니다 void, 그리고 가져 가라 object 그리고 EventArgs. 사각형 구멍과 사각형 페그와 같은 종류. 따라서 이러한 방법은 대의원과 동일한 시그니처 또는 모양을 가지고 있다고 말합니다.

따라서 메소드에 대한 참조를 만드는 방법을 알면 이벤트의 목적에 대해 생각해 봅시다. 시스템의 다른 곳에서 어떤 일이 발생하거나 "이벤트 처리"에 일부 코드가 실행되기를 원합니다. 이를 위해 실행하려는 코드에 대한 특정 메소드를 만듭니다. 이벤트와 실행 방법 사이의 접착제는 대의원입니다. 이 행사는 이벤트가 제기 될 때 호출하는 방법에 포인터의 "목록"을 내부적으로 저장해야합니다.* 물론, 방법을 호출하려면 어떤 주장이 전달되는지 알아야합니다! 우리는 대의원을 이벤트와 호출 될 모든 특정 방법 사이의 "계약"으로 사용합니다.

그래서 기본값 EventHandler (그리고 많은 사람들이 그것을 좋아합니다) a 방법의 특정 모양 (다시, void/object-eventargs). 이벤트를 선언 할 때, 당신은 말하고 있습니다 방법의 모양 (EventHandler) 그 이벤트는 대의원을 지정하여 호출됩니다.

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyEventHandler(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyEventHandler SomethingHappened;

//Here is some code I want to be executed
//when SomethingHappened fires.
void HandleSomethingHappened(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

//To raise the event within a method.
SomethingHappened("bar");

(*이것은 .NET의 이벤트의 열쇠이며 "마법"을 벗겨냅니다. 이벤트는 실제로 표지 아래에있는 것과 동일한 "모양"의 메소드 목록 만 있습니다. 목록은 이벤트가 사는 곳에 저장됩니다. 이벤트는 "제기"입니다. 실제로 "이 값을 매개 변수로 사용 하여이 값 목록을 통한"이벤트 핸들러를 할당하는 것은이 메소드 목록에 메소드를 추가하는 더 쉬운 방법 일뿐입니다. 호출).

다른 팁

C#은 두 가지 용어를 알고 있습니다. delegate 그리고 event. 첫 번째부터 시작합시다.

대리자

delegate 방법에 대한 참조입니다. 인스턴스에 대한 참조를 만들 수있는 것처럼 다음과 같습니다.

MyClass instance = myFactory.GetInstance();

대의원을 사용하여 메소드에 대한 참조를 만들 수 있습니다.

Action myMethod = myFactory.GetInstance;

메소드에 대한이 참조가 있으므로 참조를 통해 메소드를 호출 할 수 있습니다.

MyClass instance = myMethod();

하지만 왜 그렇게하겠습니까? 당신은 또한 전화 할 수 있습니다 myFactory.GetInstance() 곧장. 이 경우 가능합니다. 그러나 나머지 응용 프로그램이 지식을 갖기를 원하지 않는 곳에 대해 생각할 경우가 많습니다. myFactory 또는 전화합니다 myFactory.GetInstance() 곧장.

분명한 것은 당신이 교체 할 수 있기를 원한다면 myFactory.GetInstance() ~ 안으로 myOfflineFakeFactory.GetInstance() 하나의 중앙 장소에서 (일명 공장 방법 패턴).

공장 방법 패턴

그래서, 당신이 있다면 TheOtherClass 클래스와 사용이 필요합니다 myFactory.GetInstance(), 이것은 대의원없이 코드가 어떻게 보이는가입니다 (당신은 TheOtherClass 당신의 유형에 대해 알고 있습니다 myFactory):

TheOtherClass toc;
//...
toc.SetFactory(myFactory);


class TheOtherClass
{
   public void SetFactory(MyFactory factory)
   {
      // set here
   }

}

대의원을 사용하는 경우 내 공장 유형을 노출 할 필요가 없습니다.

TheOtherClass toc;
//...
Action factoryMethod = myFactory.GetInstance;
toc.SetFactoryMethod(factoryMethod);


class TheOtherClass
{
   public void SetFactoryMethod(Action factoryMethod)
   {
      // set here
   }

}

따라서 유형을 노출시키지 않고 사용하기 위해 다른 클래스에 대의원을 줄 수 있습니다. 당신이 노출시키는 유일한 것은 방법의 서명 (당신이 가지고있는 매개 변수 수 등)입니다.

"내 방법의 서명", 전에 어디에서 들었습니까? 오 예, 인터페이스 !!! 인터페이스는 전체 클래스의 서명을 설명합니다. 대의원을 하나의 방법의 서명을 설명하는 것으로 생각하십시오!

인터페이스와 대의원의 또 다른 큰 차이점은 수업을 작성할 때 C# "이 방법이 해당 유형의 대의원을 구현할 필요가 없다는 것입니다." 인터페이스를 사용하면 "이 클래스는 해당 유형의 인터페이스를 구현합니다"라고 말해야합니다.

또한, 대의원 참조는 (일부 제한과 함께, 아래 참조) 여러 가지 방법을 참조 할 수 있습니다 ( MulticastDelegate). 이는 대의원을 호출 할 때 여러 가지 명시 적으로 부착 된 방법이 실행됨을 의미합니다. 객체 참조는 항상 하나의 객체 만 참조 할 수 있습니다.

a MulticastDelegate (Method/Delegate) 서명에는 리턴 값이 없어야합니까 (void) 및 키워드 out 그리고 ref 서명에 사용되지 않습니다. 분명히, 당신은 숫자를 반환하고 같은 숫자를 반환 할 것으로 기대하는 두 가지 방법을 호출 할 수 없습니다. 서명이 준수되면 대의원은 자동으로 MulticastDelegate.

이벤트

이벤트는 단지 다른 오브젝트의 대의원에 가입을 드러내는 Get; Set; Set; Set; 인스턴스 필드 등) 일뿐입니다. 그러나 이러한 속성은 GET을 지원하지 않습니다. 대신, 그들은 ADD를 지원합니다. 제거하다;

그래서 당신은 다음을 가질 수 있습니다.

    Action myField;

    public event Action MyProperty
    {
        add { myField += value; }
        remove { myField -= value; }
    }

UI의 사용 (Winforms, WPF, UWP So)

이제 우리는 대의원이 방법에 대한 참조이며 세상에 대의원에서 참조 할 수있는 방법을 제공 할 수 있음을 알려주는 이벤트를 가질 수 있다는 것을 알고 있습니다. 우리는 UI 버튼입니다. 내가 클릭했는지 여부에 관심이있는 사람은 누구나 우리와 함께 방법을 등록하도록 요청할 수 있습니다 (우리가 노출 된 이벤트를 통해). 우리는 우리에게 주어진 모든 방법을 사용하여 대의원에서 참조 할 수 있습니다. 그리고 우리는 기다렸다가 기다릴 것입니다 .... 사용자가 와서 해당 버튼을 클릭 할 때까지 대의원을 호출 할 충분한 이유가 있습니다. 대의원은 우리에게 주어진 모든 방법을 참조하기 때문에 모든 방법이 호출됩니다. 우리는 이러한 방법이 무엇을하는지 모르거나 어떤 클래스가 그 방법을 구현하는지 알지 못합니다. 우리가 관심을 갖는 것은 누군가가 우리가 클릭하는 데 관심이 있었고, 우리가 원하는 서명을 준수하는 방법에 대한 참조를 주었다는 것입니다.

자바

Java와 같은 언어에는 대의원이 없습니다. 대신 인터페이스를 사용합니다. 그들이하는 방식은 '우리가 클릭 중다'에 관심이있는 사람에게 질문하고, 특정 인터페이스를 구현하도록 (우리가 호출 할 수있는 특정 메소드와 함께) 인터페이스를 구현하는 전체 인스턴스를 제공하는 것입니다. 우리는이 인터페이스를 구현하는 모든 객체의 목록을 유지하고 클릭 할 때마다 '특정 방법'을 호출 할 수 있습니다.

다음은 도움이 될 수있는 코드 예제입니다.

using System;
using System.Collections.Generic;
using System.Text;

namespace Event_Example
{
  // First we have to define a delegate that acts as a signature for the
  // function that is ultimately called when the event is triggered.
  // You will notice that the second parameter is of MyEventArgs type.
  // This object will contain information about the triggered event.

  public delegate void MyEventHandler(object source, MyEventArgs e);

  // This is a class which describes the event to the class that receives it.
  // An EventArgs class must always derive from System.EventArgs.

  public class MyEventArgs : EventArgs
  {
    private string EventInfo;

    public MyEventArgs(string Text) {
      EventInfo = Text;
    }

    public string GetInfo() {
      return EventInfo;
    }
  }

  // This next class is the one which contains an event and triggers it
  // once an action is performed. For example, lets trigger this event
  // once a variable is incremented over a particular value. Notice the
  // event uses the MyEventHandler delegate to create a signature
  // for the called function.

  public class MyClass
  {
    public event MyEventHandler OnMaximum;

    private int i;
    private int Maximum = 10;

    public int MyValue
    {
      get { return i; }
      set
      {
        if(value <= Maximum) {
          i = value;
        }
        else 
        {
          // To make sure we only trigger the event if a handler is present
          // we check the event to make sure it's not null.
          if(OnMaximum != null) {
            OnMaximum(this, new MyEventArgs("You've entered " +
              value.ToString() +
              ", but the maximum is " +
              Maximum.ToString()));
          }
        }
      }
    }
  }

  class Program
  {
    // This is the actual method that will be assigned to the event handler
    // within the above class. This is where we perform an action once the
    // event has been triggered.

    static void MaximumReached(object source, MyEventArgs e) {
      Console.WriteLine(e.GetInfo());
    }

    static void Main(string[] args) {
      // Now lets test the event contained in the above class.
      MyClass MyObject = new MyClass();
      MyObject.OnMaximum += new MyEventHandler(MaximumReached);
      for(int x = 0; x <= 15; x++) {
        MyObject.MyValue = x;
      }
      Console.ReadLine();
    }
  }
}

이는 실제로 이벤트 핸들러의 선언입니다. 이벤트가 시작될 때 호출되는 방법입니다. 이벤트를 만들려면 다음과 같은 글을 쓸 것입니다.

public class Foo
{
    public event EventHandler MyEvent;
}

그런 다음 다음과 같은 이벤트를 구독 할 수 있습니다.

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

onmyevent ()가 다음과 같이 정의됩니다.

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

언제든지 Foo 해고 MyEvent, 당신의 OnMyEvent 핸들러가 호출됩니다.

항상 인스턴스를 사용할 필요는 없습니다 EventArgs 두 번째 매개 변수로. 추가 정보를 포함하려면 파생 된 클래스를 사용할 수 있습니다. EventArgs (EventArgs 컨벤션별 기반). 예를 들어, 정의 된 일부 이벤트를 보면 Control winforms에서 또는 FrameworkElement WPF에서는 추가 정보를 이벤트 처리기에 전달하는 이벤트의 예를 볼 수 있습니다.

여기에 기존의 위대한 답변에 추가하기 위해 - 허용 된 코드의 코드를 구축하는 것은 delegate void MyEventHandler(string foo)...

컴파일러는 대의원 유형을 알고 있기 때문입니다 뭔가가 좋아졌습니다 이벤트, 이것은 :

myObj.SomethingHappened += HandleSomethingHappened;

완전히 동일합니다.

myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

그리고 핸들러도 가능합니다 미등록 ~와 함께 -= 이와 같이:

// -= removes the handler from the event's list of "listeners":
myObj.SomethingHappened -= HandleSomethingHappened;

완전성을 위해, 이벤트를 제기하는 것은 이벤트를 소유 한 수업에서만 이런 일을 할 수 있습니다.

//Firing the event is done by simply providing the arguments to the event:
var handler = SomethingHappened; // thread-local copy of the event
if (handler != null) // the event is null if there are no listeners!
{
    handler("Hi there!");
}

핸들러의 스레드-로컬 사본은 호출이 스레드-안전인지 확인하기 위해 필요합니다. 그렇지 않으면 스레드가 이동하여 이벤트의 마지막 핸들러가 이벤트에 대한 마지막 핸들러를 해제 할 수 있습니다. null, 그리고 우리는 "재미"를 가질 것입니다 NullReferenceException 거기.


C# 6 은이 패턴에 대해 멋진 짧은 손을 소개했습니다. NULL 전파 연산자를 사용합니다.

SomethingHappened?.Invoke("Hi there!");

사건에 대한 나의 이해는;

대리자:

실행될 방법 / 메소드에 대한 참조를 보유 할 변수. 이로 인해 변수와 같은 방법을 전달할 수 있습니다.

이벤트 작성 및 호출 단계 :

  1. 이 행사는 대의원의 사례입니다

  2. 이벤트는 대의원의 사례이므로 먼저 대의원을 정의해야합니다.

  3. 이벤트가 발사 될 때 실행할 방법 / 메소드를 할당합니다 (대의원을 부릅니다)

  4. 이벤트 발사 (대의원에게 전화하십시오)

예시:

using System;

namespace test{
    class MyTestApp{
        //The Event Handler declaration
        public delegate void EventHandler();

        //The Event declaration
        public event EventHandler MyHandler;

        //The method to call
        public void Hello(){
            Console.WriteLine("Hello World of events!");
        }

        public static void Main(){
            MyTestApp TestApp = new MyTestApp();

            //Assign the method to be called when the event is fired
            TestApp.MyHandler = new EventHandler(TestApp.Hello);

            //Firing the event
            if (TestApp.MyHandler != null){
                TestApp.MyHandler();
            }
        }

    }   

}

게시자 : 이벤트가 발생하는 곳. 게시자는 클래스가 사용중인 위임을 지정하고 필요한 인수를 생성하고, 그 주장을 전달하며, 대의원에게 전달해야합니다.

가입자 : 응답이 발생하는 경우. 가입자는 이벤트에 응답 할 방법을 지정해야합니다. 이 방법은 대의원과 동일한 유형의 인수를 취해야합니다. 그런 다음 가입자는이 방법을 게시자 대의원에 추가합니다.

따라서 이벤트가 게시자에서 발생하면 Delegate는 일부 이벤트 인수 (데이터 등)를받지 만 게시자는 이러한 모든 데이터에서 어떤 일이 일어날 지 전혀 모른다. 가입자는 자신의 클래스에서 방법을 만들어 게시자 수업에서 이벤트에 응답하여 가입자가 게시자의 이벤트에 응답 할 수 있습니다.

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyDelegate(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyDelegate MyEvent;

//Here is some code I want to be executed
//when SomethingHappened fires.
void MyEventHandler(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.MyEvent += new MyDelegate (MyEventHandler);

I agree with KE50 except that I view the 'event' keyword as an alias for 'ActionCollection' since the event holds a collection of actions to be performed (ie. the delegate).

using System;

namespace test{

class MyTestApp{
    //The Event Handler declaration
    public delegate void EventAction();

    //The Event Action Collection 
    //Equivalent to 
    //  public List<EventAction> EventActions=new List<EventAction>();
    //        
    public event EventAction EventActions;

    //An Action
    public void Hello(){
        Console.WriteLine("Hello World of events!");
    }
    //Another Action
    public void Goodbye(){
        Console.WriteLine("Goodbye Cruel World of events!");
    }

    public static void Main(){
        MyTestApp TestApp = new MyTestApp();

        //Add actions to the collection
        TestApp.EventActions += TestApp.Hello;
        TestApp.EventActions += TestApp.Goodbye;

        //Invoke all event actions
        if (TestApp.EventActions!= null){
            //this peculiar syntax hides the invoke 
            TestApp.EventActions();
            //using the 'ActionCollection' idea:
            // foreach(EventAction action in TestApp.EventActions)
            //     action.Invoke();
        }
    }

}   

}

Great technical answers in the post! I have nothing technically to add to that.

One of the main reasons why new features appear in languages and software in general is marketing or company politics! :-) This must not be under estimated!

I think this applies to certain extend to delegates and events too! i find them useful and add value to the C# language, but on the other hand the Java language decided not to use them! they decided that whatever you are solving with delegates you can already solve with existing features of the language i.e. interfaces e.g.

Now around 2001 Microsoft released the .NET framework and the C# language as a competitor solution to Java, so it was good to have NEW FEATURES that Java doesn't have.

I recently made an example of how to use events in c#, and posted it on my blog. I tried to make it as clear as possible, with a very simple example. In case it might help anyone, here it is: http://www.konsfik.com/using-events-in-csharp/

It includes description and source code (with lots of comments), and it mainly focuses on a proper (template - like) usage of events and event handlers.

Some key points are:

  • Events are like "sub - types of delegates", only more constrained (in a good way). In fact an event's declaration always includes a delegate (EventHandlers are a type of delegate).

  • Event Handlers are specific types of delegates (you may think of them as a template), which force the user to create events which have a specific "signature". The signature is of the format: (object sender, EventArgs eventarguments).

  • You may create your own sub-class of EventArgs, in order to include any type of information the event needs to convey. It is not necessary to use EventHandlers when using events. You may completely skip them and use your own kind of delegate in their place.

  • One key difference between using events and delegates, is that events can only be invoked from within the class that they were declared in, even though they may be declared as public. This is a very important distinction, because it allows your events to be exposed so that they are "connected" to external methods, while at the same time they are protected from "external misuse".

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top