A tradução do artigo foi preparada especificamente para os alunos do curso "Desenvolvedor C #" .

O que são eventos em c #?
Um evento pode ser usado para fornecer notificações. Você pode se inscrever no evento se precisar dessas notificações. Você também pode criar seus próprios eventos que o notificarão de que algo do seu interesse aconteceu. O .NET Framework oferece tipos internos que você pode usar para criar eventos. Usando delegados, expressões lambda e métodos anônimos, você pode criar e usar eventos de uma maneira conveniente.
Noções básicas sobre delegados em C #
Em C #, os delegados formam os blocos de construção básicos para eventos. Um delegado é um tipo que define a assinatura de um método. Por exemplo, em C ++, isso pode ser feito usando um ponteiro de função. Em C #, você pode criar uma instância de um delegado que aponte para outro método. Você pode chamar esse método através da instância delegada.
A seguir, é apresentado um exemplo de declarar um delegado e chamar um método por meio dele.
Usando um delegado em C #
}class Program { public delegate double MathDelegate(double value1, double value2); public static double Add(double value1, double value2) { return value1 + value2; } public static double Subtract(double value1, double value2) { return value1 - value2; } Console.ReadLine(); public static void Main() { MathDelegate mathDelegate = Add; var result = mathDelegate(5, 2); Console.WriteLine(result);
Como você pode ver, usamos a palavra-chave delegate para informar ao compilador que estamos criando um tipo de delegado.
É fácil instanciar delegados junto com a criação automática de um novo tipo de delegado.
Você também pode usar a
nova palavra-chave para criar um representante.
MathDelegate mathDelegate = new MathDelegate(Add)
;
Um delegado instanciado é um objeto; Você também pode usá-lo e passar como argumento para outros métodos.
Delegados de difusão seletiva em c #
Outra grande característica dos delegados é que você pode combiná-los. Isso é chamado de multicasting. Você pode usar o operador + ou + = para adicionar outro método à lista de chamadas de uma instância delegada existente. Da mesma forma, você também pode remover um método da lista de chamadas usando o operador de atribuição de decremento (- ou - =). Esse recurso serve como base para eventos em C #. A seguir, é apresentado um exemplo de um delegado multicast.
class Program { static void Hello(string s) { Console.WriteLine(" Hello, {0}!", s); } static void Goodbye(string s) { Console.WriteLine(" Goodbye, {0}!", s); } delegate void Del(string s); static void Main() { Del a, b, c, d;
Isso é possível porque os delegados herdam da classe
System.MulticastDelegate
, que por sua vez herda de
System.Delegate
. Você pode usar os membros definidos nessas classes base para seus delegados.
Por exemplo, para descobrir quantos métodos um representante de multicast chamará, você pode usar o seguinte código:
int invocationCount = d.GetInvocationList().GetLength(0);
Covariância e contravariância em C #
Quando você atribui um método a um delegado, a assinatura do método não precisa corresponder exatamente ao delegado. Isso é chamado de covariância e contravariância. A covariância permite que um método tenha um tipo de retorno mais derivado do que o definido no delegado. A contravariância permite um método com tipos de parâmetros que são menos derivados que tipos no delegado.
Delegar covariância
Aqui está um exemplo de covariância,
class Program { public delegate TextWriter CovarianceDel(); public static StreamWriter MethodStream() { return null; } public static StringWriter MethodString() { return null; } static void Main() { CovarianceDel del; del = MethodStream; del = MethodString; Console.ReadLine(); } }
Como o
StreamWriter
e o
StringWriter
herdam do
TextWriter
, você pode usar o
CovarianceDel
com os dois métodos.
Contravariância em delegados
A seguir, é apresentado um exemplo de contravariância.
class Program { public static void DoSomething(TextWriter textWriter) { } public delegate void ContravarianceDel(StreamWriter streamWriter); static void Main() { ContravarianceDel del = DoSomething; Console.ReadLine(); } }
Como o método
DoSomething
pode funcionar com o
TextWriter
, certamente pode funcionar com o
StreamWriter
. Devido à contravariância, você pode chamar um delegado e passar uma instância do
StreamWriter
para o método
DoSomething
.
Você pode aprender mais sobre esse conceito
aqui .
Expressões lambda em c #
Às vezes, uma assinatura de método inteira pode exigir mais código que o corpo do próprio método. Também há situações em que você precisa criar um método inteiro apenas para usá-lo como um representante.
Para esses casos, a Microsoft adicionou alguns novos recursos em C #, como métodos anônimos na 2.0. No C # 3.0, as coisas ficaram ainda melhores quando expressões lambda foram adicionadas. A expressão lambda é a maneira preferida ao escrever um novo código.
A seguir, é apresentado um exemplo da sintaxe lambda mais recente.
class Program { public delegate double MathDelegate(double value1, double value2); public static void Main() { MathDelegate mathDelegate = (x,y) => x + y; var result = mathDelegate(5, 2); Console.WriteLine(result); // : 7 mathDelegate = (x, y) => x - y; ; result = mathDelegate(5, 2); Console.WriteLine(result); // : 3 Console.ReadLine(); } }
Para ler este código, você precisa usar a palavra “segue” no contexto da sintaxe lambda especial. Por exemplo, a primeira expressão lambda no exemplo acima diz "xey seguem a adição de xey".
Uma função lambda não possui um nome específico, diferente de um método. Por esse motivo, as lambdas são chamadas de funções anônimas. Você também não precisa especificar explicitamente o tipo do valor de retorno. O compilador assume automaticamente a partir do seu lambda. E no caso do exemplo acima, os tipos de parâmetro x e y também não são especificados explicitamente.
Você pode criar lambdas que abrangem vários operadores. Você pode fazer isso adicionando chaves em volta das instruções que compõem o lambda, conforme mostrado no exemplo abaixo.
MathDelegate mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; };
Às vezes, um anúncio de delegado para um evento parece um pouco complicado. Por esse motivo, o .NET Framework possui vários tipos de delegados internos que você pode usar ao declarar delegados. No exemplo MathDelegate, você usou o seguinte delegado:
public delegate double MathDelegate(double value1, double value2);
Você pode substituir esse representante por um dos tipos
Func <int, int, int>
, a saber
Func <int, int, int>
.
assim
class Program { public static void Main() { Func<int, int, int> mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; }; var result = mathDelegate(5, 2); Console.WriteLine(result);
Os tipos de funções <...> podem ser encontrados no espaço para nome do sistema. Eles representam delegados que retornam um tipo e levam de 0 a 16 parâmetros. Todos esses tipos são herdados de System.MulticaseDelegate, para que você possa adicionar vários métodos à lista de chamadas.
Se você precisar de um tipo de delegado que não retorne um valor, poderá usar os tipos System.Action. Eles também podem assumir de 0 a 16 parâmetros, mas não retornam um valor.
Aqui está um exemplo do uso do tipo Action,
class Program { public static void Main() { Action<int, int> mathDelegate = (x,y) => { Console.WriteLine(x + y); }; mathDelegate(5, 2);
Você pode aprender mais sobre os representantes internos do .NET
aqui .
As coisas ficam complicadas quando sua função lambda começa a se referir a variáveis declaradas fora da expressão lambda ou a isso. Normalmente, quando um controle deixa o escopo de uma variável, a variável se torna inválida. Mas e se o delegado se referir a uma variável local. Para corrigir isso, o compilador gera código que prolonga a vida útil da variável capturada, pelo menos enquanto o delegado durar mais tempo. Isso é chamado de encerramento.
Você pode aprender mais sobre fechamentos
aqui .
Eventos em C #
Considere um padrão de desenvolvimento popular - publicador-assinante (pub / sub). Você pode se inscrever em um evento e será notificado quando o editor do evento iniciar um novo evento. Este sistema é usado para estabelecer uma comunicação fraca entre componentes em um aplicativo.
O delegado forma a base para o sistema de eventos em C #.
Um evento é um tipo especial de delegado que facilita a programação orientada a eventos. Eventos são membros de uma classe que não pode ser chamada fora da classe, independentemente do especificador de acesso. Portanto, por exemplo, um evento declarado como público permitiria que outras classes usassem + = e - = para esse evento, mas o acionamento de um evento (ou seja, chamar um delegado) é permitido apenas na classe que contém o evento. Vamos ver um exemplo,
Em seguida, um método em outra classe pode se inscrever no evento adicionando um de seus métodos ao delegado do evento:
A seguir, é apresentado um exemplo que mostra como uma classe pode fornecer um representante aberto e gerar um evento.
class Program { static void Main(string[] args) {
Mesmo se o evento for declarado como
public
, ele não poderá ser acionado diretamente em qualquer lugar, exceto na classe em que está localizado.
Usando a palavra-chave
event
, o compilador protege nosso campo de acessos indesejados.
E também
Não permite o uso de = (atribuição direta de delegação). Portanto, seu código agora está protegido contra o risco de excluir assinantes anteriores usando = em vez de + =.
Além disso, você pode observar a sintaxe especial de inicialização do campo OnChange para um representante vazio, como o
delegate { }
. Isso garante que nosso campo OnChange nunca seja nulo. Portanto, podemos remover a verificação nula antes de invocar o evento se não houver outros membros da classe tornando-o nulo.
Quando você executa o programa acima, seu código cria uma nova instância do Pub, assina o evento de duas maneiras diferentes e gera um evento chamando p.Raise. A classe Pub não tem conhecimento de nenhum dos assinantes. Apenas gera um evento.
Você também pode ler meu artigo,
C # Publisher-Subscriber Design Pattern, para uma compreensão mais profunda desse conceito.
Bem, isso é tudo por agora. Espero que você entenda a idéia. Obrigado por ler o post. Entre em contato se houver algum erro ou alteração nos comentários abaixo. Agradecemos antecipadamente!
Links úteis
www.c-sharpcorner.com/blogs/c-sharp-generic-delegates-func-action-and-predicatedocs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariancehttps://web.archive.org/web/20150707082707/http://diditwith.net/PermaLink,guid,235646ae-3476-4893-899d-105e4d48c25b.aspx