2010-02-01 23 views
10

Sulla base della mia risposta a this question, voglio controllare qualcosa sulla mia comprensione della prossima dynamic tipo per C# 4.Il tipo "dinamico" può variare in modo sicuro in una raccolta generica <dynamic>?

In questo caso, abbiamo una collezione che rappresenta campi di un record tirato da una tabella di database sconosciuta . Il codice meno recente (pre.Net 4) richiede elementi di tipo hold di tipo Object. Meriti di una tale raccolta a parte, mi chiedo cosa succede quando si cambia Object a dynamic.

Da un lato, mi aspetto che dal momento che tutte le cose per i tipi dinamici sono state elaborate in fase di esecuzione, tutto dovrebbe andare bene fintanto che il programmatore non commette errori di battitura sul tipo previsto di un particolare oggetto nella collezione.

D'altra parte, mi chiedo sulla parola "tutto" nella frase precedente. Il runtime potrebbe forse memorizzare i risultati della cache al primo accesso a una proprietà dinamica, causando il fallimento delle chiamate successive che utilizzano tipi diversi?

risposta

3

Ecco un po 'rilevante dal blog di Sam che parla brevemente della politica di caching.

http://blogs.msdn.com/samng/archive/2008/10/29/dynamic-in-c.aspx

Il DLR controlla una cache per vedere se il data azione è già stata legata contro l'attuale serie di argomenti. Quindi nel nostro esempio, faremmo una corrispondenza tipo basata su 1, 2, e il tipo di runtime di d. Se abbiamo un riscontro nella cache, , restituiamo il risultato memorizzato nella cache. Se non abbiamo un riscontro cache, il DLR controlla se il ricevitore è un IDynamicObject.Questi ragazzi sono oggetti essenzialmente che sa come prendersi cura del proprio legame, come ad come oggetti COM IDispatch, reali dinamiche oggetti come Ruby o Python quelli, o qualche oggetto .NET che implementa l'interfaccia IDynamicObject. Se è uno di questi, il DLR chiama all'IDO e chiede di associare l'azione .

Si noti che il risultato del richiamo dell'IDO da associare è un albero di espressioni che rappresenta il risultato del collegamento. Se non è un IDO, le chiamate DLR nel raccoglitore di lingua (nel nostro caso , il raccoglitore di runtime C#) per associare l'operazione . Il legatore di runtime C# vincolerà l'azione e restituirà un albero di espressioni che rappresenta il risultato del bind . Dopo il passaggio 2 o 3 , l'albero di espressioni risultante viene unito al meccanismo di memorizzazione nella cache in modo che eventuali chiamate successive a possano essere eseguite contro la cache anziché essere rimbalzate.

Tuttavia, ciò che Sam non menziona è esattamente ciò che è la politica di mancanza della cache. Esistono due criteri di cache-miss principali: (1) attivano un errore di cache quando i tipi di argomento cambiano, (2) attivano un errore di cache quando cambiano le identità degli argomenti.

Ovviamente il primo è molto più performante; risolvendo quando possiamo memorizzare nella cache esclusivamente in base al tipo è difficile. Un'esegesi dettagliata di come tutta quella logica funzionerebbe richiederebbe molto tempo; spero che io o Chris o Sam faremo un post sul blog su uno di questi giorni.

+0

Questo è un po 'quello di cui ero preoccupato. Nel mio semplice esempio è abbastanza facile per il runtime sapere che sono tipi diversi. Ma la memorizzazione nella cache avviene e quindi, se dovessi fare un sacco di questi, sarebbe possibile solo imbattersi in un caso limite. In realtà, però, non penso che sarà un problema per il caso che è stata posta questa domanda, che è bene sapere. –

+3

@Joel: Certo, potrebbero esserci dei bug nella politica di miss cache. Se ne trovi qualcuno, fammi sapere! :) –

1

Va bene, piuttosto che aspettare per una risposta che sparato su Visual Studio 2010 Beta 2, e questo programma di test viene eseguito bene:

class Foo 
{ 
    public string foo = "Foo!"; 
} 
class Bar 
{ 
    public int bar = 42; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var test = new List<dynamic>(); 
     test.Add(new Foo()); 
     test.Add(new Bar()); 

     Console.WriteLine(test[0].foo.Substring(0,3)); 
     Console.WriteLine(test[1].bar.ToString("000")); 

     Console.ReadKey(true); 
    } 
} 

ho voluto fare in modo che non solo ho verifico proprietà con nomi diversi, ma che avevano anche diversi tipi e che ho usato una funzionalità in ogni tipo che sono incompatibili tra loro. Questo sembra per suggerire che se il numero è memorizzato nella cache, il runtime è sufficientemente intelligente da sapere quando utilizzare la cache e quando non farlo. Mi piacerebbe ancora sentire se qualcuno conosce un caso limite in cui questo potrebbe non reggere, o un commento più autorevole sul perché lo farà.

1

Si può pensare allo zucchero sintattico come solo sintattico per scrivere tutte le chiamate di metodo usando Reflection e MethodInfo.Invoke() - sotto il cofano non funziona esattamente così, ma si può pensare che funzioni in quel modo , con tutti i "richiami 1000 metodi/sec tramite dynamic => assassinato perf" considerazioni che lo accompagnano.

+1

"Non funziona esattamente così" è un'esagerazione. Non funziona * niente del genere * se si utilizza il raccoglitore C#. –

+0

@Eric Giusto abbastanza, e hai ragione, ma ai fini della concettualizzazione di come funziona 'dinamico' è stato più facile dare la spiegazione della "resistenza al vento disprezzo" –

1

Per quanto riguarda la dizionario/lista è interessato, si può solo vedere object. dynamic è in gran parte negli occhi di chi guarda - cioè il chiamando il codice; sotto il cappuccio è "oggetto più un po 'di zucchero". Quindi non dovresti vedere nessun problema qui.

Dimostrazione:

static void Main() 
    { 
     Console.WriteLine(IsObject<int>()); // false 
     Console.WriteLine(IsObject<object>()); // true 
     Console.WriteLine(IsObject<dynamic>()); // true 
     Console.WriteLine(IsObject<string>()); // false 
    } 
    static bool IsObject<T>() 
    { 
     return typeof(T) == typeof(object); 
    } 
Problemi correlati