O remetente de um evento sempre deve ser um objeto genérico?

10

Ao programar eventos em C #, é recomendável criar um delegado na forma de:

delegate XEventHandler(object sender, XEventArgs e);

Minha pergunta está no primeiro argumento do delegado object sender,. Sempre tem que ser genérico object? Ter um remetente do tipo objectsempre resulta em código semelhante a este.

val = ((ConcreteType)sender).Property;

ou, ainda mais detalhado,

ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }

Um argumento contra remetentes fortemente tipados é que outros objetos podem encaminhar o evento sem se preocupar com o tipo. Embora isso possa fazer sentido em ambientes de GUI, não tenho certeza se isso pode se beneficiar fora de uma GUI.

E se a classe do remetente for sempre conhecida (pelo menos como uma classe abstrata)? Por exemplo, se estou implementando um ListChangedevento em uma Listclasse abstrata , e se outras classes vão herdá-lo (por exemplo LinkedList, ArrayList), está certo definir meu delegado com um remetente do tipo List?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

Ou haveria uma desvantagem em mudar o convencional object senderpara um tipo mais específico?

sampathsris
fonte

Respostas:

10

Neste ponto, é principalmente uma convenção (bastante forte). Ou seja, será estranho se você escrever uma biblioteca que não segue essa convenção.

As Diretrizes de design de eventos dizem:

FAZER uso objectcomo o tipo do primeiro parâmetro do manipulador de eventos, e chamá-lo sender.

No entanto, você pode observar que as orientações atuais dizem que você não deve definir seu próprio delegado personalizado para eventos, mas usar EventHandler<T>, se possível.

Quanto ao design, acho que ele também promove a reutilização de manipuladores de eventos, mesmo em contextos não originalmente previstos pelo designer original do evento.

jhominal
fonte
2
Ughhh ... só porque a Microsoft decidiu tornar suas diretrizes genéricas o suficiente para serem aplicáveis ​​a todos, não significa que é uma boa idéia para todos seguirem suas diretrizes. É muito provável que "todo mundo" não esteja escrevendo código para ser usado por milhões de outros desenvolvedores. Eu me apaixonei por cerca de 2/3 das recomendações do link que você forneceu.
Dunk
Para dizer a verdade, essa "diretriz" parece mais ou menos com a notação húngara da API do Windows. Alguém brilhante começou por um bom motivo e então todo mundo começou a abusar. Quando há uma diretriz, é melhor haver uma boa razão por trás dessa diretriz. E o que eu acho que o motivo dessa diretriz é que o System.Windows.Formsespaço para nome é o local onde os eventos são mais usados ​​e fazia sentido assinar o Clickevento de Buttonou a CheckBox. Assim, o remetente precisa ser genérico. ...
sampathsris
... Mas quando se trata de outras áreas de funcionalidade mais específicas e contidas, o remetente pode não precisar ser uma classe genérica. Veja novamente meu exemplo de uma hierarquia de classes de Lists.
Sampathsris
11
@ Dunk: E esse é o ponto. Essa diretriz vem das Diretrizes de design da estrutura, que se preocupam principalmente com o código consumido por outras pessoas . Não porque é a melhor solução, mas porque é a menos surpreendente. Essa é a melhor opção para uma estrutura . Para bibliotecas menores, se o caso de uso estiver bem especificado, menos orientações serão aplicáveis. A Microsoft diz isso explicitamente no início do livro.
Magus
11
Não estou discutindo com a resposta, até a votei porque veio de uma fonte respeitável. Só estou dizendo que não usaria as diretrizes. Se um evento deve enviar dados específicos, enviarei apenas os dados específicos. Além disso, o recurso de evento funciona bem se você usá-los como eles deveriam ser usados.
Dunk
0

O motivo da recomendação é que ela permite alterações futuras que não necessariamente exigem alterações no código existente e, especialmente, na interface pública.

O próprio mecanismo de evento ainda pode ser usado para eventos no estilo "VB6", mas você precisará alterar todos os consumidores existentes se precisar alterar a assinatura (ou pior: criar novas versões dos mesmos eventos). Com a abordagem recomendada, desde que os itens mais recentes sejam herdados dos existentes, é possível atualizar a assinatura sem corrigir o código existente.

Mark Hurd
fonte