Metodo di estensione e oggetto dinamico


96

Riassumerò il mio problema nel seguente frammento di codice.

List<int> list = new List<int>() { 5, 56, 2, 4, 63, 2 };
Console.WriteLine(list.First());

Il codice sopra funziona correttamente.

Ora ho provato quanto segue

dynamic dList = list;
 Console.WriteLine(dList.First());

ma ricevo RuntimeBinderException. Perché è così?


Questo mi sembra un duplicato di questa domanda ha chiesto appena 4 giorni fa stackoverflow.com/questions/5270782/...
jbtule

@jbtule La differenza è che thisqui è dinamico, ma se atterri qui, dovresti probabilmente guardare anche a questa domanda
nik.shornikov

Risposte:


131

Per espandere la risposta di Stecya ... i metodi di estensione non sono supportati dalla digitazione dinamica sotto forma di metodi di estensione , cioè chiamati come se fossero metodi di istanza. Tuttavia, questo funzionerà:

dynamic dList = list;
Console.WriteLine(Enumerable.First(dList));

Naturalmente, questo può o non può essere utile. Se potessi fornire maggiori informazioni sul perché e su come stai cercando di utilizzare la digitazione dinamica, potremmo essere in grado di aiutarti di più.


Stavo giocando con un oggetto dinamico e ho ottenuto questa eccezione. Hai scritto un articolo su questo argomento, dove utilizzare o meno un oggetto dinamico
santosh singh

19
@geek: Personalmente la mia regola pratica è usare solo dynamicdove è veramente necessario ... fondamentalmente se accedessi ai membri con riflessione, questo è un grande segno. D'altra parte, io sono un duro stampatore statico - altri potrebbero suggerire politiche meno pessimistiche :)
Jon Skeet

2
Potrebbe essere più leggibile eseguire il cast al tipo conosciuto, funziona: Console.WriteLine (((List <int>) dList) .First ()); Oppure Console.WriteLine ((dList as List <int>) .First ()) ;.
AVee

138

Per espandere la risposta di Jon, il motivo per cui questo non funziona è perché nei metodi di estensione del codice regolari e non dinamici funzionano facendo una ricerca completa di tutte le classi note al compilatore per una classe statica che ha un metodo di estensione che corrisponde. La ricerca procede in ordine in base alla nidificazione dello spazio dei nomi e alle usingdirettive disponibili in ogni spazio dei nomi.

Ciò significa che per ottenere la corretta risoluzione del richiamo di un metodo di estensione dinamico, in qualche modo il DLR deve sapere in fase di esecuzione quali erano tutti gli annidamenti e le usingdirettive dello spazio dei nomi nel codice sorgente . Non abbiamo un meccanismo a portata di mano per codificare tutte queste informazioni nel sito della chiamata. Abbiamo preso in considerazione l'idea di inventare un meccanismo del genere, ma abbiamo deciso che era un costo troppo alto e produceva troppi rischi di pianificazione per valerne la pena.


Grazie mille per la spiegazione.
santosh singh

3
È una caratteristica del genere in vista? Sarebbe certamente un cambiamento radicale; le chiamate che attualmente lanciano RunTimeBinderExceptions inizierebbero improvvisamente a funzionare durante la ricompilazione dell'origine. Inoltre, ci sarebbero rischi per la sicurezza associati all'implementazione di tale funzionalità?
Ani

5
@ani: Stiamo progettando di implementare questa funzionalità? No. Ci sono rischi per la sicurezza? Non ne sono a conoscenza; che tipo di rischio per la sicurezza avevi in ​​mente? Inizia dicendo chi è l'attaccante e quale minaccia sta facendo all'utente.
Eric Lippert

@EricLippert, ho capito che tutti gli dynamicoggetti sono uguali a C # :, DynamicObjectquindi non c'è modo di differenziarli ed è uno dei motivi per cui non è possibile aggiungere metodi di estensione dynamic, giusto?
Tom Sarduy

@EricLippert valuta la possibilità di espandere ulteriormente questa risposta e di aggiungere una frase del tipo "Quando uno qualsiasi dei parametri è dinamico, tutte le risoluzioni vengono posticipate fino al runtime". Anche se per te è ovvio che questa parte importante è difficile da trovare altrove su SO (vedi stackoverflow.com/questions/48324768 per esempio)
Alexei Levenkov

18

Perché First()non è un metodo di List. È definito nell'estensione Linq aIEnumerable<>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.