2010-03-19 20 views
11

Così ho letto MSDN e Stack Overflow. Capisco cosa fa l'Action Delegate in generale, ma non è fare clic non importa quanti esempi faccio. In generale, lo stesso vale per l'idea dei delegati. Quindi questa è la mia domanda. Quando hai una funzione come questa:Spiegare i delegati .NET

public GetCustomers(Action<IEnumerable<Customer>,Exception> callBack) 
{ 
} 

Che cos'è questo e cosa dovrei passare ad esso?

risposta

9

si aspetta una funzione che prende IEnumerable e l'eccezione e restituisce void.

void SendExceptionToCustomers(IEnumerable<Customer> customers, Exception ex) { 
    foreach(var customer in customers) 
     customer.SendMessage(ex.Message); 
} 

GetCustomers(SendExceptionToCustomers); 

btw, GetCustomers sembra un nome terribile per questa funzione - è chiedere un'azione, quindi il suo più come DoSomethingToCustomers

EDIT in risposta a commentare


Ok, ha senso, quindi ora perché preoccuparsi di avere una funzione GetCustomer? Non posso fare la stessa cosa con la tua funzione se io lo rinomassi semplicemente GetCustomer?

Bene, quello che sta accadendo qui è che il chiamante può specificare qualche azione.GetCustomers Supponiamo che è implementato in questo modo:

public void GetCustomers(Action<Enumerable<Customer>, Exception> handleError) { 
    Customer[] customerlist = GetCustomersFromDatabase(); 
    try { 
     foreach(var c in customerList) 
      c.ProcessSomething() 
    } catch (Exception e) { 
     handleError(customerList, e); 
    } 
} 

allora si potrebbe chiamare GetCustomers da qualche parte su un programma a riga di comando, e passarlo

GetCustomers((list, exception) => { 
    Console.WriteLine("Encountered error processing the following customers"); 
    foreach(var customer in list) Console.WriteLine(customer.Name); 
    Console.WriteLine(exception.Message); 
}); 

mentre si potrebbe chiamare GetCustomers da un'applicazione remota, per esempio, e passarlo

Getcustomers((list, exception) => { 
    // code that emails me the exception message and customer list 
}) 


Inoltre, il commento di Slak suggerisce un altro motivo per il parametro delegato - GetCusto mers recupera i clienti, ma in modo asincrono. Ogni volta che viene effettuato il recupero dei clienti, chiama la funzione che gli viene assegnata con la lista clienti o un'eccezione, se si è verificata un'eccezione.

+0

concordato sul cattivo nome. –

+0

Sembra che il callback riceva i clienti che sono stati caricati (o un'eccezione) dopo che i clienti hanno caricato in modo asincrono. – SLaks

+2

Mi piacerebbe fare qualcosa ai clienti la maggior parte del tempo, specialmente quando sono fastidiosi. –

3

Un delegato è una classe che punta a una o più funzioni. È possibile richiamare un'istanza delegata, che chiamerà le funzioni a cui punta.

Nel tuo caso, la funzione GetCustomers accetta una seconda funzione come parametro.

La seconda funzione deve assumere due parametri di tipo IEnumerable<Customer> e Exception.

Per chiamare GetCustomers, è necessario effettuare una seconda funzione per chiamare, quindi passarlo a un delegato contenente la seconda funzione.

Ad esempio:

static void GetCustomersCallback(IEnumerable<Customer> customers, Exception ex) { 
    //Do something... 
} 

//Elsewhere: 
GetCustomers(new Action<IEnumerable<Customer>,Exception>(GetCustomersCallback)); 

Questa chiamata crea una nuova istanza delegato che punta alla funzione GetCustomersCallback, e passa il delegato alla funzione GetCustomers. GetCustomers chiamerà presumibilmente la richiamata dopo che i clienti hanno terminato il caricamento e passerà i clienti caricati come parametro.
Si può anche lasciare fuori l'istanza delegato e passare direttamente alla funzione:

GetCustomers(GetCustomersCallback); 
+0

Non credo che sia una classe, è un tipo di riferimento separato tutto da solo: http://msdn.microsoft.com/en-us/library/900fyy8e(VS.71).aspx –

+0

@Nick: 'System.Delegate' è una classe; puoi vederlo in Riflettore – SLaks

0

Si potrebbe passare un metodo vuoto che prende un IEnumerable e un'eccezione come parametri ...

Diciamo che avete questo metodo:

public void DoSomeStuffWithCustomers(
    IEnumerable<Customer> customers, Exception exception) 
{  
} 

Si potrebbe chiamare il metodo GetCustomers in questo modo:

GetCustomers(DoSomeStuffWithCustomers); 
2

si può chiamare con un lambda

GetCustomers((cust, ex) => { 
    //do something here} 
); 
1

È solo una versione aggiornata dei puntatori di funzione di C con la possibilità di essere collegata a un'istanza di oggetto se si tratta di un puntatore di metodo oggetto non statico (i C++ li chiamavano puntatori di metodo quando aggiungevano oggetti e indicatori di funzione insieme).

La firma del tipo può essere resa generica utilizzando le caratteristiche del generico di C#.

Tutta la roba dei generici sta solo templatizzando la firma.

Il delegato del nome è scelto male (a meno che non si pensi a tutte le nostre app guidate dai framework). Perché l'uso non è sempre "delegare". Spesso è il codice a cui hai delegato delle responsabilità (un iteratore, per esempio) che chiama il "delegato" che hai precedentemente inviato. Ecco perché spesso vedi il termine callback.

Le richiamate sono state tradizionalmente utilizzate in framework per il codice dell'applicazione da chiamare nel mezzo di un ciclo o quando si verifica un evento particolare. Ti permette di far sì che il tuo codice accada nel mezzo di un altro codice - in effetti, è solo l'unico modo all'interno di un thread.

Ovviamente, i gestori di eventi .NET sono i delegati che vengono chiamati dal framework in momenti appropriati, e puoi accettare delegati nelle tue funzioni e chiamarli appropriati per permetterti di rendere il tuo codice un po 'generico/riutilizzabile/organizzato.

0

Hanno confuso l'inferno fuori di me fino a quando ho letto:

  1. spiegazione di Andrew Troelsen dei quali in Pro C# 2008 and the .Net 3.5 Platform
  2. Il capitolo sul pattern Observer in Head First Design Patterns

Questo secondo libro è di circa java, e non menziona i delegati, ma spiega bene un problema che i delegati aiutano a risolvere: comunicazione tra classi.

1

Semplicemente? Puntatori di funzione

+1

Non solo puntatori di funzione. Una combinazione di un puntatore di funzione e di alcuni dati che è garantito essere di un tipo adatto per l'uso con quella funzione. – supercat