code

빈 C # 이벤트 처리기를 자동으로 만들기

codestyles 2020. 11. 6. 08:17
반응형

빈 C # 이벤트 처리기를 자동으로 만들기


연결된 처리기가없는 C #에서는 이벤트를 발생시킬 수 없습니다. 따라서 각 호출 전에 이벤트가 null인지 확인해야합니다.

if ( MyEvent != null ) {
  MyEvent( param1, param2 );
}

내 코드를 가능한 한 깨끗하게 유지하고 이러한 null 검사를 제거하고 싶습니다. 적어도 내 경우에는 성능에 크게 영향을 미치지 않을 것이라고 생각합니다.

MyEvent( param1, param2 );

지금은 각 이벤트에 수동으로 빈 인라인 처리기를 추가하여이 문제를 해결합니다. 기억해야하므로 오류가 발생하기 쉽습니다.

void Initialize() {
  MyEvent += new MyEvent( (p1,p2) => { } );
}

리플렉션과 일부 CLR 매직을 사용하여 지정된 클래스의 모든 이벤트에 대해 빈 처리기를 자동으로 생성하는 방법이 있습니까?


나는 이것을 다른 게시물에서 보았고 뻔뻔하게 훔쳐서 그 이후로 내 코드의 대부분에서 사용했습니다.

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

//Let you do this:
public void DoSomething() {
    Click(this, "foo");
}

//Instead of this:
public void DoSomething() {
    if (Click != null) // Unnecessary!
        Click(this, "foo");
}

*이 기술의 기원을 아는 사람이 있으면 댓글에 게시 해주세요. 나는 출처가 정당한 신용을 받고 있다고 정말로 믿습니다.

( 편집 : 나는이 게시물 에서 C #의 숨겨진 기능을 얻었 습니까? )


표기법 :

if ( MyEvent != null ) {
  MyEvent( param1, param2 );
}

스레드로부터 안전하지 않습니다. 다음과 같이해야합니다.

EventHandler handler = this.MyEvent;
if ( null != handler ) { handler( param1, param2 ); }

나는 이것이 귀찮다는 것을 이해하므로 도우미 방법을 할 수 있습니다.

static void RaiseEvent( EventHandler handler, object sender, EventArgs e ) {
    if ( null != handler ) { handler( sender, e ); }
}

그리고 전화 :

RaiseEvent( MyEvent, param1, param2 );

C # 3.0을 사용하는 경우 도우미 메서드를 확장 메서드로 선언 할 수 있습니다.

static void Raise( this EventHandler handler, object sender, EventArgs e ) {
    if ( null != handler ) { handler( sender, e ); }
}

그리고 전화 :

MyEvent.Raise( param1, param2 );

또한 다른 이벤트 처리기에 대한 다음 확장 / 도우미 메서드를 만들 수 있습니다. 예를 들면 :

static void Raise<TEventArgs>( this EventHandler<TEventArgs> handler,
    object sender, TEventArgs e ) where TEventArgs : EventArgs
{
    if ( null != handler ) { handler( sender, e ); }
}

C # 6.0에서는 조건부 null 연산자 덕분에 null 검사를 수행하기 위해 이러한 길이로 이동할 필요가 없습니다. ?.

The docs explain that calling MyEvent?.Invoke(...) copies the event to a temporary variable, performs the null check, and if not null, calls Invoke on the temporary copy. This isn't necessarily thread-safe in every sense, as someone could have added a new event after the copy to the temporary variable, which wouldn't be called. It does guarantee you won't call Invoke on null though.

In short:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click;

public void DoSomething() {
    Click?.Invoke(this, "foo");
}

You can write is as:

MyEvent += delegate { };

I am not sure what you want to do is correct.


You don't need several extension methods for different event handlers, you just need one:

public static class EventHandlerExtensions {
  public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs {
    if (handler != null) handler(sender, args);
  }
}

This is a bad idea in that the code which is consuming the event now has an expectation that the object with the event has been coded with an action by default. If your code is never going to be used anywhere else by anyone else then I guess you can get away with it.


C# event declarations unfortunately include a number of well-known safety problems and inefficiencies. I designed a number of extension methods on delegates to invoke them safely, and to register/unregister delegates in a thread-safe manner.

Your old event-raising code:

if (someDelegate != null) someDelegate(x, y, z);

Your new code:

someDelegate.Raise(x, y, z);

Your old event registration code:

event Action fooEvent;
...
lock (someDummyObject) fooEvent += newHandler;

Your new code:

Action fooEvent;
...
Events.Add(ref fooEvent, newHandler);

No locking needed, no compiler-inserted dummy objects used to lock the events.


You can use PostSharp to on build time add this magic. It is the best way.

참고URL : https://stackoverflow.com/questions/340610/create-empty-c-sharp-event-handlers-automatically

반응형