Se os eventos são implementados como delegados em .NET, que é o ponto da seção IL .event?

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

Pergunta

Eu vi algumas perguntas muito boas no Stack Overflow relativos delegados, eventos e a implementação .NET dessas duas características. Uma questão em particular, " Como C # Eventos trabalhar nos bastidores ? ", produziu uma grande resposta que explica alguns pontos sutis muito bem.

A resposta para a pergunta acima torna este ponto:

Quando você declarar um evento de campo-like ... o compilador gera os métodos e um campo privado (do mesmo tipo como o delegado). Dentro da classe, quando se refere a ElementAddedEvent você está se referindo ao campo. Lado de fora a classe, você está se referindo ao campo

artigo Um MSDN ligada a partir da mesma pergunta ( " campo-like eventos ") acrescenta:

A noção de criar um evento é precisamente equivalente a invocar o delegado representado pelo evento - Assim, não há nenhuma linguagem especial construções para gerar eventos.

Querendo continuar a analisar, eu construí um projeto de teste, a fim de ver o IL que um evento e um delegado são compilados para:

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

    public TestClass()
    { }
}

Eu esperava que o handler campo delegado eo FooEvent evento para compilar para aproximadamente o mesmo código IL, com alguns métodos adicionais para embrulhar o acesso ao campo FooEvent gerado pelo compilador. Mas o IL gerado não era bem o que eu esperava:

.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
}

Uma vez que os eventos são nada mais do que delegados com métodos add e remove gerados pelo compilador, eu não esperava para ver os eventos tratados como algo mais do que no IL. Mas os métodos de adicionar e remover são definidos em uma seção que começa .event, não .method como métodos normais são.

As minhas questões últimas são: se os eventos são implementados simplesmente como delegados com métodos de acesso, o que é o ponto de ter uma seção IL .event? Eles não poderiam ser implementados em IL sem isso usando seções .method? É .event equivalente a .method?

Foi útil?

Solução

Eu não tenho certeza que é surpreendente ... comparar com o mesmo para propriedades vs campos (desde propriedades antes de a mesma função que eventos: encapsulamento via acessores):

.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)
}

Também - eventos não mencionou nada sobre campos; eles única definir os acessores (Adicionar / Remover). O corpo de apoio delegado é um detalhe de implementação; isso só acontece que os eventos de campo como-declarar um campo como um membro de apoio - da mesma forma que implicam programas de auto-propriedades declarar um campo como um membro de apoio. Outras implementações é possível (e muito comum, especialmente em formas etc).

Outras implementações comuns:

esparsos-eventos (controlos, etc.) - EventHandlerList (ou similar):

// 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);
}

(o anterior é bastante-muito a espinha dorsal de eventos-formas Win)

Fachada (embora isso confunde o "remetente" um pouco, algum código intermediário é frequentemente útil):

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

(a lata acima também ser utilizado para mudar o nome eficazmente um evento)

Outras dicas

Os eventos não são o mesmo que delegados. Eventos encapsular adicionar / remover um manipulador para um evento. O manipulador é representado com um delegado.

Você pode apenas escrever AddClickHandler / RemoveClickHandler etc para cada evento -. Mas seria relativamente doloroso, e não torná-lo fácil para ferramentas como VS para separar os eventos de qualquer outra coisa

Este é apenas como propriedades realmente -. Você poderia escrever GetSize / SetSize etc (como você faz em Java), mas por separar propriedades, existem atalhos sintáticas disponíveis e melhor suporte a ferramentas

O ponto de ter eventos que são um par de adicionar, remover métodos é encapsulamento .

A maioria dos eventos de tempo são usados ??como é, mas outras vezes você não deseja armazenar os delegados ligados ao evento em um campo, ou você quer fazer o processamento extra em adicionar ou remover métodos de eventos.

Por exemplo, uma maneira de implementar eventos eficientes memória é armazenar os delegados em um dicionário em vez de um campo privado, porque os campos sempre são alocados enquanto um dicionário só cresce em tamanho quando itens são adicionados. Este modelo é semelhante com o que WinForms e usos WPF fazer fazer uso eficiente de memória (winforms e WPF usa dicionários com chave para armazenar os delegados não listas)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top