이벤트가 .NET에서 대의원으로 구현되면 .Event IL 섹션의 요점은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/219815

문제

대의원, 이벤트 및이 두 기능의 .NET 구현에 관한 스택 오버플로에서 아주 좋은 질문을 보았습니다. 특히 한 가지 질문이 있습니다. "C# 이벤트는 무대 뒤에서 어떻게 작동합니까?", 몇 가지 미묘한 점을 잘 설명하는 훌륭한 대답을 만들었습니다.

위의 질문에 대한 답은 다음과 같은 점을 만듭니다.

필드와 같은 이벤트를 선언 할 때 ... 컴파일러는 대의원과 동일한 유형의 메소드와 개인 필드를 생성합니다. 수업 내에서 ElementAddedEvent를 언급 할 때 필드를 언급합니다. 수업 밖에서, 당신은 현장을 언급하고 있습니다

같은 질문에서 연결된 MSDN 기사 ( "현장과 같은 이벤트") 추가 :

이벤트를 제기한다는 개념은 이벤트로 대표되는 대의원을 호출하는 것과 정확히 동일합니다. 따라서 이벤트를 제기하기위한 특별한 언어 구성은 없습니다.

더 조사하고 싶을 때, 나는 이벤트와 대의원이 다음과 같이 편집 된 IL을보기 위해 테스트 프로젝트를 구축했습니다.

public class TestClass
{
    public EventHandler handler;
    public event EventHandler FooEvent;

    public TestClass()
    { }
}

나는 대의원들을 기대했다 handler 그리고 이벤트 FooEvent 컴파일러 생성에 대한 액세스를 랩핑하는 몇 가지 추가 방법과 함께 대략 동일한 IL 코드로 컴파일하려면 FooEvent 필드. 그러나 생성 된 IL은 내가 기대했던 것이 아닙니다.

.class public auto ansi beforefieldinit TestClass
    extends [mscorlib]System.Object
{
    .event [mscorlib]System.EventHandler FooEvent
    {
        .addon instance void TestClass::add_FooEvent(class [mscorlib]System.EventHandler)
        .removeon instance void TestClass::remove_FooEvent(class [mscorlib]System.EventHandler)
    }

    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        // Constructor IL hidden
    }

    .field private class [mscorlib]System.EventHandler FooEvent
    .field public class [mscorlib]System.EventHandler handler
}

이벤트는 컴파일러 생성 대의원에 지나지 않습니다 add 그리고 remove 방법, 나는 IL에서 이벤트가 그 이상으로 취급되는 것을 기대하지 않았다. 그러나 추가 및 제거 방법은 시작되는 섹션에 정의됩니다. .event, 아니다 .method 정상적인 방법으로.

나의 궁극적 인 질문은 다음과 같습니다. 이벤트가 단순히 액세서 방법을 가진 대의원으로 구현되는 경우 .event IL 섹션? 이를 사용하여 IL에서 구현할 수 없었습니다. .method 섹션? ~이다 .event 동등합니다 .method?

도움이 되었습니까?

해결책

나는 그것이 놀랍지 확신하지 못한다 ... 속성 대 필드와 비교할 때 (이벤트와 동일한 함수 이전의 속성이기 때문에 : 액세서를 통한 캡슐화) :

.field public string Foo // public field
.property instance string Bar // public property
{
    .get instance string MyType::get_Bar()
    .set instance void MyType::set_Bar(string)
}

또한 - 이벤트 하지 마라 필드에 대해 언급합니다. 그들 액세서를 정의합니다 (추가/제거). 대의원 후원자는 구현 세부 사항입니다. 현장과 같은 이벤트는 자동 구현 분비자가 필드를 후원 구성원으로 선언하는 것과 같은 방식으로 필드를 후원 구성원으로 선언하는 것입니다. 다른 구현이 가능합니다 (특히 양식 등에 매우 일반적).

기타 공통 구현 :

Sparse -Events (컨트롤 등) - EventHandlerList (또는 이와 유사한) :

// only one instance field no matter how many events;
// very useful if we expect most events to be unsubscribed
private EventHandlerList events = new EventHandlerList();
protected EventHandlerList Events {
    get { return events; } // usually lazy
}

// this code repeated per event
private static readonly object FooEvent = new object();
public event EventHandler Foo
{
    add { Events.AddHandler(FooEvent, value); }
    remove { Events.RemoveHandler(FooEvent, value); }
}
protected virtual void OnFoo()
{
    EventHandler handler = Events[FooEvent] as EventHandler;
    if (handler != null) handler(this, EventArgs.Empty);
}

(위의 것은 윈-형식 이벤트의 백본입니다)

외관 (이것은 "발신자"를 혼란스럽게하지만 일부 중개 코드는 종종 도움이됩니다) :

private Bar wrappedObject; // via ctor
public event EventHandler SomeEvent
{
    add { wrappedObject.SomeOtherEvent += value; }
    remove { wrappedObject.SomeOtherEvent -= value; }
}

(위의 것은 또한 이벤트의 이름을 효과적으로 바꿀 수 있습니다)

다른 팁

이벤트는 대의원과 동일하지 않습니다. 이벤트는 이벤트의 핸들러 추가/제거를 캡슐화합니다. 핸들러는 대의원으로 표시됩니다.

~할 수 있었다 모든 이벤트에 대해 AddClickHandler/RemoveClickHandler 등을 작성하십시오. 그러나 비교적 고통스럽고 도구가 다른 어떤 것과 이벤트를 분리하기 쉽지 않습니다.

이것은 속성과 같습니다. getsize/setsize 등을 쓸 수 있지만 (Java에서와 같이) 속성을 분리하면 구문 단축이 사용 가능하고 도구 지원이 향상됩니다.

추가, 제거, 메소드 인 이벤트가있는 점은 캡슐화.

대부분의 시간 이벤트는 그대로 사용되지만 다른 시간에는 필드에 이벤트에 첨부 된 대의원을 저장하거나 이벤트 메소드 추가 또는 제거에 대한 추가 처리를하고 싶지 않습니다.

예를 들어 구현하는 한 가지 방법입니다 메모리 효율적인 이벤트 필드는 항상 할당되는 반면 사전은 항목이 추가 될 때만 크기가 커지기 때문에 대의원을 개인 필드가 아닌 사전에 보관하는 것입니다. 이 모델은 Winforms 및 WPF가 사용하는 것과 유사합니다. 메모리를 효율적으로 사용합니다 (Winforms 및 WPF는 주요 사전을 사용하여 대의원을 저장하지 않음 목록을 저장합니다).

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