2015-07-30 16 views
14

Proprio imbattuto in questo oggiPerché non si può usare la funzione anon con un parametro dinamico?

una funzione anonima o il gruppo metodo non può essere usato come un valore costituente di un'operazione legata in modo dinamico.

quando si cerca di fare

static R ifNotNull<R>(dynamic o, Func<dynamic, R> returnFunc, R otherwise) { 
    return ReferenceEquals(null, o) ? otherwise : returnFunc(o); 
} 

e utilizzarlo con

dynamic firstAddress = ...; 
return ifNotNull<string>(firstAddress, (a) => a.address_1, null) 

Ora la maggior parte delle limitazioni sulle dinamiche senso per me - non è possibile utilizzare un metodo di estensione perché come il compilatore dovrebbe decidere quale statico compilarlo? Ma non capisco questo qui. Da dove viene la confusione? Qual è esattamente la limitazione?

+2

C'è probabilmente un problema con la compilazione '(a) => a.address_1' in un' returnFunc'.In attesa di Eric Lippert per rispondere a questa domanda :-) – dasblinkenlight

+0

A proposito, qual è la differenza tra il tuo codice e 'statico R ifNotNull (oggetto o, Func returnFunc, R altrimenti) {...}'? – dasblinkenlight

+0

@dasblinkenlight esattamente quello che stavo pensando. Prepararsi a Lippert in 3..2..1 ... –

risposta

11

Qual è il tipo statico di lambaa => a.address_1? Potresti essere tentato di dire che è un Func<dynamic, dynamic>. Ma ricordate:

Un'espressione lambda è una funzione anonima che è possibile utilizzare per creare delegati o tipi di albero di espressione.

Quindi forse è un Expression<Func<dynamic, dynamic>>. Un lamda da solo non ha un solo tipo statico.

Ora normalmente l'inferenza di tipo potrebbe capire che si sta passando il lamba a una funzione che prende uno Func e verrà convertito in un delegato in fase di compilazione. Tuttavia quando si chiama con argomenti dinamici the method call is dispatched dynamically.

Se si dispone di una chiamata di metodo con un argomento dinamico, viene inviato dinamicamente, , punto. Durante il runtime binding, tutti i tipi statici dei tuoi argomenti sono noti (emphasis mine) e i tipi vengono scelti per gli argomenti dinamici in base ai loro valori effettivi.

Quindi il fatto che il metodo prende un Func non è prendere in considerazione, dal momento che the actual method call isn't determined until runtime quindi non c'è nessun tipo di inferenza.

Per ottenere questo per compilare dovrete lanciare la vostra Lamba ad un Func<dynamic, string> come di seguito:

return ifNotNull<string>(firstAddress, new Func<dynamic, string>((a) => a.address_1), null); 

Ora il tipo statico del vostro Lamda è noto.

+0

Grazie per la risposta solida. Ciò ha senso. Anche se sono ancora un po 'stanco, non ho avuto una risposta lippert ... –

1

Intendevo dire che è necessario eseguire il metodo lambda per l'espressione desiderata desiderata. Quindi funzionerà bene.

Ti piace questa:

return ifNotNull(firstAddress, (Func<dynamic, string>)((a) => a.address_1), null);