2016-05-02 15 views
25

Ho recentemente iniziato a lavorare con C# e c'è qualcosa che ho usato facilmente in Python che vorrei ottenere in C#.Dizionari e funzioni

Per esempio, ho una funzione simile:

def my_func(): 
return "Do some awesome stuff" 

e un dizionario come:

my_dic = {"do": my_func} 

ho fatto uno script in cui quando l'utente avrebbe ingresso "fare", il programma chiamerebbe my_func secondo il dizionario.

Mi piacerebbe sapere come posso assegnare le funzioni alle stringhe in un dizionario C#.

+0

@SiyavashHamdi: No, non è così. Hai solo bisogno di delegati, come lo standard 'Action' o' Func'. O 'Expression's. Naturalmente sono tutti basati internamente sulla riflessione, dal momento che 'MethodInfo' è da qualche parte all'interno di ognuno di questi, ma non è come trovarlo/invocarlo manualmente. – quetzalcoatl

+2

Vedere anche: [Delegati] (https://msdn.microsoft.com/library/ms173171.aspx) e in particolare i tipi di delegati generici incorporati [Azione] (https://msdn.microsoft.com/library/system. action.aspx) (per i metodi con tipo di ritorno 'void') e [Func] (https://msdn.microsoft.com/de-de/library/bb534960.aspx) (per i metodi con tipo di ritorno non -'void) e i loro numerosi overload. – Corak

risposta

50

Sostanzialmente nello stesso modo:

static void Main() { 
    var dict = new Dictionary<string, Action>(); 
    // map "do" to MyFunc 
    dict.Add("do", MyFunc); 
    // run "do" 
    dict["do"](); 
} 

static void MyFunc() { 
    Console.WriteLine("Some stuff"); 
} 
+3

Puoi anche fare espressioni lambda: 'dict.Add (" do ",() => Console.WriteLine (" Some stuff "));'. La chiave qui è che 'Action' è un tipo delegato e specifica che la funzione non deve accettare parametri e non restituire alcun risultato. Esistono altre versioni generiche di 'Action' che consentono di prendere argomenti, e' Func' consente di restituire un valore. Vale anche la pena notare che, per far funzionare tutto questo, tutte le funzioni richiedono lo stesso set di parametri e il tipo di output. – jpmc26

+1

A differenza di Python C# ha un lambda multilinea a proposito:() => {Console.WriteLine ("A"); Console.WriteLine ("B"); }, dal momento che non è limitato dal "istinto" del suo creatore. – Traubenfuchs

+0

@Traubenfuchs Per essere onesti con Python, è possibile eseguire funzioni multiline in qualsiasi ambito tramite 'def' molto tempo prima (credo)' lambda' è stato aggiunto alla lingua. Quindi la limitazione ha senso quando si considera 'lambda' come una comodità per l'inlining di operazioni molto semplici e il fatto che i lambda multiespressione probabilmente complicheranno l'analisi immensamente o richiedono una tonnellata di elementi di sintassi. Al contrario, non è possibile definire le normali funzioni (che sono parti di classi) in un ambito di funzione con C#, quindi le funzioni lambda riempiono più ruoli in C# di quanto non facciano in Python. – jpmc26

18

È possibile usufruire della sintassi di inizializzazione collezione qui.

var my_dic = new Dictionary<string, Action> 
{ 
    { "do", my_func } 
}; 

Per le funzioni più sofisticate, si dovrebbe sostituire Action nella dichiarazione con la Function tipo appropriato.

+0

Per casi banali si può anche usare la sintassi lambda nell'inizializzatore della raccolta (e in alcuni casi basta scrivere il nome del gruppo metodo) – kai

5

C frammenti # codice che sarebbero più direttamente analogo ai tuoi esempi sono:

string my_func() { 
    return "Do some awesome stuff"; 
} 

E:

var my_dic = new Dictionary<string, Func<string>> { 
    { "do", my_func }, 
}; 

Il trucco, come gli altri utenti hanno fatto notare, è quello di creare un stringa il cui tipo di valore generico è o un'azione (che è un metodo che restituisce void) o un Func <T> (che è un metodo che restituisce un oggetto di tipo T).

In entrambi i casi, si potrebbe quindi eseguire il metodo con:

var result = my_dic["do"](); 
+0

Ho aggiunto la mia risposta, nonostante sia molto simile alle risposte di Evk e Adam E, dato che nessuno di loro ha fornito analoghi di codice diretto dell'esempio fornito da Balgy. –

2

Se si vuole veramente il comportamento dinamico di Python (vale a dire essere in grado di assegnare e chiamare i metodi che hanno diverse firme per un "dizionario senza soluzione di continuità "), Andrei con ExpandoObject che era specificamente pensato per essere in grado di avere il CLR per supportare linguaggi dinamici come Python (vedi IronPython, et al).

static void Main() 
{ 
    dynamic expando = new ExpandoObject(); 
    expando.Do = new Func<string>(MyFunc); 
    expando.Do2 = new Func<string, string>(MyFunc2); 

    Console.WriteLine(expando.Do()); 
    Console.WriteLine(expando.Do2("args")); 
} 

static string MyFunc() 
{ 
    return "Do some awesome stuff"; 
} 

static string MyFunc2(string arg) 
{ 
    return "Do some awesome stuff with " + arg; 
} 

Se si preferisce, si può anche trattare un ExpandoObject come un dizionario:

static void Main(string[] args) 
{ 
    dynamic expando = new ExpandoObject(); 
    var dict = (IDictionary<string, object>) expando; 
    dict["Do"] = new Func<string>(MyFunc); 
    dict["Do2"] = new Func<string, string>(MyFunc2); 

    Console.WriteLine(expando.Do()); 
    Console.WriteLine(expando.Do2("args")); 
} 

static string MyFunc() 
{ 
    return "Do some awesome stuff"; 
} 

static string MyFunc2(string arg) 
{ 
    return "Do some awesome stuff with " + arg; 
} 

** Modifica **

completa divulgazione: Questa domanda sembra molto simile (se non una vittima) di String- Function dictionary c# where functions have different arguments, che ho appena risposto allo stesso modo.