Qual é o seu uso de delegados em C #?
Qual é o seu uso de delegados em C #?
Respostas:
Agora que temos expressões lambda e métodos anônimos em C #, uso muito mais delegados. Em C # 1, onde você sempre tinha que ter um método separado para implementar a lógica, usar um delegado geralmente não fazia sentido. Hoje em dia eu uso delegados para:
Os delegados são muito úteis para muitos propósitos.
Uma dessas finalidades é usá-los para filtrar sequências de dados. Nesse caso, você usaria um delegado de predicado que aceita um argumento e retorna verdadeiro ou falso, dependendo da implementação do próprio delegado.
Aqui está um exemplo bobo - tenho certeza de que você pode extrapolar algo mais útil com isso:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>
{
"Nicole Hare",
"Michael Hare",
"Joe Hare",
"Sammy Hare",
"George Washington",
};
// Here I am passing "inMyFamily" to the "Where" extension method
// on my List<String>. The C# compiler automatically creates
// a delegate instance for me.
IEnumerable<String> myFamily = names.Where(inMyFamily);
foreach (String name in myFamily)
Console.WriteLine(name);
}
static Boolean inMyFamily(String name)
{
return name.EndsWith("Hare");
}
}
static Boolean inMyFamily(String name)
método é o delegado. Onde leva um delegado como parâmetro. Uma vez que delegados são apenas ponteiros de função quando você passa o nome do método para o .Where(delegate)
que se torna o delegado. Como inMyFamily retorna um tipo booleano, ele é considerado um predicado. Predicados são apenas delegados que retornam booleanos.
Encontrei outra resposta interessante:
Um colega de trabalho acabou de me fazer esta pergunta - qual é o ponto de delegados em .NET? Minha resposta foi muito curta e que ele não encontrou online: atrasar a execução de um método.
Fonte: LosTechies
Exatamente como o LINQ está fazendo.
Você pode usar delegados para declarar variáveis e parâmetros com tipo de função.
Exemplo
Considere o padrão de "empréstimo de recursos". Você deseja controlar a criação e a limpeza de um recurso, enquanto permite que o código do cliente "pegue emprestado" o recurso intermediário.
Isso declara um tipo de delegado.
public delegate void DataReaderUser( System.Data.IDataReader dataReader );
Qualquer método que corresponda a essa assinatura pode ser usado para instanciar um delegado desse tipo. No C # 2.0, isso pode ser feito implicitamente, simplesmente usando o nome do método, bem como usando métodos anônimos.
Este método usa o tipo como parâmetro. Observe a invocação do delegado.
public class DataProvider
{
protected string _connectionString;
public DataProvider( string psConnectionString )
{
_connectionString = psConnectionString;
}
public void UseReader( string psSELECT, DataReaderUser readerUser )
{
using ( SqlConnection connection = new SqlConnection( _connectionString ) )
try
{
SqlCommand command = new SqlCommand( psSELECT, connection );
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while ( reader.Read() )
readerUser( reader ); // the delegate is invoked
}
catch ( System.Exception ex )
{
// handle exception
throw ex;
}
}
}
A função pode ser chamada com um método anônimo da seguinte maneira. Observe que o método anônimo pode usar variáveis declaradas fora de si mesmo. Isso é extremamente útil (embora o exemplo seja um pouco artificial).
string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";
DataProvider.UseReader( sQuery,
delegate( System.Data.IDataReader reader )
{
Console.WriteLine( sTableName + "." + reader[0] );
} );
Os delegados geralmente podem ser usados no lugar de uma interface com um método; um exemplo comum disso seria o padrão do observador. Em outros idiomas, se você deseja receber uma notificação de que algo aconteceu, você pode definir algo como:
class IObserver{ void Notify(...); }
Em C #, isso é mais comumente expresso por meio de eventos, em que o manipulador é um delegado, por exemplo:
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
Outro ótimo lugar para usar delegados se você precisar passar um predicado para uma função, por exemplo, ao selecionar um conjunto de itens de uma lista:
myList.Where(i => i > 10);
A descrição acima é um exemplo da sintaxe lambda, que também poderia ter sido escrita da seguinte maneira:
myList.Where(delegate(int i){ return i > 10; });
Outro lugar onde pode ser útil usar delegados é registrar funções de fábrica, por exemplo:
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
Eu espero que isso ajude!
Estou chegando nisso muito tarde, mas estava tendo problemas para descobrir o propósito dos delegados hoje e escrevi dois programas simples que fornecem a mesma saída que eu acho que explica bem seu propósito.
NoDelegates.cs
using System;
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Test.checkInt(1);
Test.checkMax(1);
Test.checkMin(1);
Test.checkInt(10);
Test.checkMax(10);
Test.checkMin(10);
Test.checkInt(20);
Test.checkMax(20);
Test.checkMin(20);
Test.checkInt(30);
Test.checkMax(30);
Test.checkMin(30);
Test.checkInt(254);
Test.checkMax(254);
Test.checkMin(254);
Test.checkInt(255);
Test.checkMax(255);
Test.checkMin(255);
Test.checkInt(256);
Test.checkMax(256);
Test.checkMin(256);
}
}
Delegates.cs
using System;
public delegate void Valid(int a);
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Valid v1 = new Valid(Test.checkInt);
v1 += new Valid(Test.checkMax);
v1 += new Valid(Test.checkMin);
v1(1);
v1(10);
v1(20);
v1(30);
v1(254);
v1(255);
v1(256);
}
}
Um uso ligeiramente diferente é acelerar a reflexão; isto é, em vez de usar reflexão a cada vez, você pode usar Delegate.CreateDelegate
para criar um delegado (digitado) para um método (a MethodInfo
) e chamar esse delegado. Isso é muito mais rápido por chamada, pois as verificações já foram feitas.
Com o Expression
, você também pode fazer o mesmo para criar código em tempo real - por exemplo, você pode criar facilmente um Expression
que representa o operador + para um tipo escolhido em tempo de execução (para fornecer suporte de operador para genéricos, que a linguagem não fornece) ; e você pode compilar um Expression
para um delegado digitado - trabalho feito.
Os delegados são usados sempre que você usa eventos - esse é o mecanismo pelo qual eles funcionam.
Além disso, os delegados são muito úteis para coisas como o uso de consultas LINQ. Por exemplo, muitas consultas LINQ usam um delegado (frequentemente Func<T,TResult>
) que pode ser usado para filtragem.
Um exemplo pode ser visto aqui . Você tem um método para processar um objeto que atende a certos requisitos. No entanto, você deseja processar o objeto de várias maneiras. Em vez de criar métodos separados, você pode simplesmente atribuir um método de correspondência que processa o objeto a um delegado e passa o delegado ao método que seleciona os objetos. Dessa forma, você pode atribuir métodos diferentes para o método de um seletor. Tentei tornar isso facilmente compreensível.
Eu uso delegados para me comunicar com threads.
Por exemplo, posso ter um aplicativo win forms que baixa um arquivo. O aplicativo inicia um thread de trabalho para fazer o download (o que evita que a GUI seja travada). O thread de trabalho usa delegados para enviar mensagens de status (por exemplo, progresso do download) de volta ao programa principal, para que a GUI possa atualizar a barra de status.
Para manipulador de eventos
Para passar o método em parâmetros de um método
Eventos, outras operações anynch
Sempre que quiser encapsular o comportamento, mas invoque-o de maneira uniforme. Manipuladores de eventos, funções de retorno de chamada, etc. Você pode realizar coisas semelhantes usando interfaces e casts, mas às vezes, o comportamento não está necessariamente vinculado a um tipo ou objeto . Às vezes, você apenas tem um comportamento que precisa encapsular.
Inicialização de parâmetro lenta! Além de todas as respostas anteriores (padrão de estratégia, padrão de observador, etc.), os delegados permitem que você lide com a inicialização lenta de parâmetros. Por exemplo, suponha que você tenha uma função Download () que leva muito tempo e retorna um certo DownloadedObject. Este objeto é consumido por um Storage dependendo de certas Condições. Normalmente, você:
storage.Store(conditions, Download(item))
Porém, com delegados (mais precisamente, lambdas) você pode fazer o seguinte, alterando a assinatura da loja para que ela receba uma Condição e uma Func <Item, DownloadedObject> e use-a assim:
storage.Store(conditions, (item) => Download(item))
Portanto, o storage só avaliará o delegado se necessário, executando o download dependendo das condições.
Uso de delegados
O parâmetro de comparação em In Array.Sort (matriz T [], comparação de comparação), List.Sort (comparação de comparação), etc.
Pelo que eu sei, os delegados podem ser convertidos em ponteiros de função. Isso torna a vida MUITO mais fácil ao interoperar com código nativo que usa ponteiros de função, pois eles podem ser efetivamente orientados a objetos, mesmo que o programador original não tenha feito nenhuma provisão para que isso aconteça.
Delegate's são usados para chamar um método por sua referência. Por exemplo:
delegate void del_(int no1,int no2);
class Math
{
public static void add(int x,int y)
{
Console.WriteLine(x+y);
}
public static void sub(int x,int y)
{
Console.WriteLine(x-y);
}
}
class Program
{
static void Main(string[] args)
{
del_ d1 = new del_(Math.add);
d1(10, 20);
del_ d2 = new del_(Math.sub);
d2(20, 10);
Console.ReadKey();
}
}