2012-12-10 5 views
7

Sto lentamente prendendo in giro i delegati, in quanto la firma del delegato deve corrispondere a quella del metodo che sta delegando anche.Come funziona la parola di delega rispetto alla creazione di un delegato

Tuttavia, si prega di rivedere il seguente codice.

public static void Save() 
{ 
    ThreadStart threadStart = delegate 
    { 
     SaveToDatabase(); 
    }; 
    new Thread(threadStart).Start(); 
} 

private static void SaveToDatabase() { } 

ora sto perplesso a questo punto, perché il delegato ritorna void (come è quello che SaveToDatabase() è) ma, è chiaramente la restituzione di un ThreadStart ... o è?

Se dovessi scrivere il mio delegato, non avrei idea di come ottenere ciò perché il delegato dovrebbe essere nullo per corrispondere al tipo restituito SaveToDatabase(). Ma non può essere; sarebbe di tipo ThreadStart!

La mia domanda è: ho completamente capito male o questo è reso possibile da alcuni trucchi .NET? Se volessi scrivere questo metodo ma creare il mio delegato, come dovrei?

+0

perché non 'ThreadStart threadStart = new ThreadStart (SaveToDatabase);' – Anirudha

+0

Non penso che venga restituito nulla poiché non esiste una parola chiave 'return'. Penso che venga creato un nuovo 'thread' che eseguirà il metodo indicato dal delegato. –

+0

@ Some1.Kill.The.DJ: in effetti, a lungo termine, prenderà alcuni parametri. – Dave

risposta

4

ora sto perplesso a questo punto, perché il delegato restituisce void (come quello è ciò che è SaveToDatabase()), ma, è chiaramente restituire un ThreadStart ... O è?

Se dovessi raddrizzare il mio delegato, non avrei idea di come ottenere ciò perché il delegato dovrebbe essere vuoto per corrispondere al tipo restituito di SaveToDatabase(), ma non può essere perché sarebbe di digita ThreadStart!

ThreadStart definito come delegato. In realtà, è definito come

public delegate void ThreadStart(); 

Quindi il codice non restituisce un delegato o un ThreadStart. Si tratta semplicemente di definire una funzione che corrisponde alla definizione di delegato ThreadStart. Il costruttore Thread prevede un delegato ThreadStart, che è stato definito come variabile threadStart, che punta alla funzione SaveToDatabase.

Tendo a pensare ai delegati come al vecchio termine C++ "puntatori di funzione". I delegati ci permettono di specificare quale tipo di funzione (parametri e tipo di ritorno) deve essere passato come parametro ad un'altra funzione.

La mia domanda è, ho completamente capito male o questo è reso possibile da alcuni trucchi .NET? Se volessi scrivere questo metodo ma creare il mio delegato, come dovrei?

Penso che potresti aver frainteso. Ma per rispondere in modo specifico a questa domanda, il metodo da scrivere dovrebbe solo corrispondere alla definizione specificata dal tipo delegato, in questo caso ThreadStart. Tale definizione del metodo deve restituire void e non accettare parametri.Il metodo SaveToDatabase corrisponde a questo tipo di delegato ed è pertanto il metodo di delega appropriato da creare.

+0

È solo un metodo che restituisce il nulla. Il codice costruttore di ThreadStart() è un mezzo per costruire il codice del puntatore delegato. Si potrebbe facilmente passare semplicemente il nome del metodo che corrisponde al tipo di delegato ThreadStart al costruttore Thread. – villecoder

2

Quando si sta per eseguire un sottoprocesso amministrato, il metodo che sta per essere eseguito viene rappresentato da ThreadStart o ParameterizedThreadStart, ma SaveToDatabase è void e sarà eseguito con void firma, non con ThreadStart tipo.

Esempio da MSDN:

class Test 
{ 
    static void Main() 
    { 
     // To start a thread using a static thread procedure, use the 
     // class name and method name when you create the ThreadStart 
     // delegate. Beginning in version 2.0 of the .NET Framework, 
     // it is not necessary to create a delegate explicityly. 
     // Specify the name of the method in the Thread constructor, 
     // and the compiler selects the correct delegate. For example: 
     // 
     // Thread newThread = new Thread(Work.DoWork); 
     // 
     ThreadStart threadDelegate = new ThreadStart(Work.DoWork); 
     Thread newThread = new Thread(threadDelegate); 
     newThread.Start(); 

     // To start a thread using an instance method for the thread 
     // procedure, use the instance variable and method name when 
     // you create the ThreadStart delegate. Beginning in version 
     // 2.0 of the .NET Framework, the explicit delegate is not 
     // required. 
     // 
     Work w = new Work(); 
     w.Data = 42; 
     threadDelegate = new ThreadStart(w.DoMoreWork); 
     newThread = new Thread(threadDelegate); 
     newThread.Start(); 
    } 
} 

class Work 
{ 
    public static void DoWork() 
    { 
     Console.WriteLine("Static thread procedure."); 
    } 
    public int Data; 
    public void DoMoreWork() 
    { 
     Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    } 
} 
+0

Quindi, se avessi creato il mio delegato, sarebbe comunque di tipo vuoto? – Dave

+0

È possibile creare la propria funzione. SaveToDatabase, SaveToDatabase2, SaveAgainToDatabase, se questi metodi sono nulli, è possibile passarli al costruttore ThreadStart –

+0

Controllare l'esempio di codice da msdn che ho postato. Ha il DoWork In un'altra classe con la firma non valida –

2

Da MSDN

Un delegato è un tipo che fa riferimento a un metodo. Quando a un delegato viene assegnato un metodo, si comporta esattamente come quel metodo. Il metodo delegato può essere utilizzato come qualsiasi altro metodo, con parametri e un valore di ritorno, come in questo esempio:

public delegate int PerformCalculation(int x, int y); 

Così tipo del delegato ritorno corrisponderà al tipo di ritorno del metodo è delegando.

Qualsiasi metodo che corrisponda alla firma del delegato, che consiste del tipo di ritorno e dei parametri, può essere assegnato al delegato. Ciò rende possibile modificare a livello di codice le chiamate di metodo e anche inserire il nuovo codice nelle classi esistenti. Finché si conosce la firma del delegato, è possibile assegnare il proprio metodo delegato.

5

La parola "delegato" è un po 'abusata. È più facile con classi e oggetti. Una "classe" è come un progetto per un oggetto. Un "oggetto" è un'istanza reale in memoria, che segue il progetto della classe.

Per i delegati usiamo la stessa parola, quindi sospetto la tua confusione. Considera il seguente codice:

class Main 
{ 
    public delegate int DelegateType(string x); 
    public int SomeFunction(string y) { return int.Parse(y)*2; } 
    public void Main() 
    { 
     DelegateType delegateInstance = null; 
     delegateInstance = SomeFunction; 
     int z = delegateInstance("21"); 
     Console.WriteLine(z); 
    } 
} 

Questo codice emette "42".

Il DelegateType è il tipo del delegato. Come una classe è un progetto per un oggetto, il delegato è un progetto per una funzione .

In seguito creiamo una variabile denominata delegateInstance che è del tipo DelegateType. A tale variabile, possiamo assegnare la funzione ANY che accetta un singolo parametro di stringa e restituisce un numero intero. Nota che abbiamo assegnato alla funzione stessa, non i risultati di tale funzione. È come se la variabile delegateInstance sia ora un sinonimo di quella funzione. Infatti, come dimostrato in seguito, possiamo ora usare delegateInstance per chiamare quella funzione! Proprio come se lo delegateInstance fosse una funzione stessa. Ma dato che è variabile, possiamo anche fare tutte le stesse cose che usiamo di solito con le variabili - come passarle come parametri ad altre funzioni, o anche tornare da altre funzioni (Una funzione che restituisce una funzione! !)

OK, vediamo il codice che ti ha sconcertato.

public static void Save() 
{ 
    ThreadStart threadStart = delegate 
    { 
     SaveToDatabase(); 
    }; 
    new Thread(threadStart).Start(); 
} 

private static void SaveToDatabase() { } 

La prima cosa da notare è che è stato utilizzato un anonymous delegate. Un altro uso improprio del termine. Quando compilato, si traduce in qualcosa di simile:

public static void Save() 
{ 
    ThreadStart threadStart; 
    threadStart = __ASDASDASD6546549871; 
    var tmp = new Thread(threadStart); 
    tmp.Start(); 
} 

private static void SaveToDatabase() { } 

private void __ASDASDASD6546549871() 
{ 
    SaveToDatabase(); 
} 

Nota che la funzione anonima è stato effettivamente trasformato in una funzione del tutto regolare con un nome casuale, e quindi che la funzione è stato assegnato alla variabile threadStart.

Quindi ora questo è proprio come nell'esempio sopra.Basta sostituire DelegateType con ThreadStart, delegateInstance con threadStart e SomeFunction con __ASDASDASD6546549871.

Ha senso ora?

+0

Questo è davvero buono - grazie mille per aver dedicato del tempo a spiegarlo, ha aiutato così tanto. Grazie. – Dave

Problemi correlati