2009-04-30 10 views
6

Non intendo il casting dinamico nel senso di trasmettere un'interfaccia inferiore o una classe base a una classe più derivata, cioè prendere una definizione di interfaccia che ho creato e quindi trasmettere dinamicamente a quell'interfaccia un oggetto diverso NON derivato da quella interfaccia ma supporta tutte le chiamate.Il C# 4 consentirà "casting dinamico"? In caso negativo, dovrebbe C# supportarlo?

Per esempio,

interface IMyInterface 
{ 
    bool Visible 
    { 
     get; 
    } 
} 

TextBox myTextBox = new TextBox(); 
IMyInterface i = (dynamic<IMyInterface>)myTextBox; 

Ciò potrebbe essere realizzato al momento della compilazione per i tipi conosciuti, e runtime per le istanze dichiarate con dinamica. La definizione dell'interfaccia è nota, così come il tipo (in questo esempio) in modo che il compilatore possa determinare se l'oggetto supporta le chiamate definite dall'interfaccia ed eseguire un po 'di magia per noi per avere il cast.

La mia ipotesi è che questo non è supportato in C# 4 (non sono riuscito a trovare un riferimento ad esso), ma mi piacerebbe sapere con certezza. E se non lo è, mi piacerebbe discutere se dovrebbe essere incluso in una futura variante della lingua o meno, e le ragioni pro e contro. Per me, sembra una buona aggiunta per abilitare un maggiore polimorfismo nel codice senza dover creare tipi completamente nuovi per racchiudere i tipi di framework esistenti.

Aggiornamento
Per timore che qualcuno mi accusano di plagio, non ero a conoscenza di Jon Skeet having already proposed this. Comunque, è bello sapere che abbiamo pensato a una sintassi estremamente simile, il che suggerisce che potrebbe essere almeno intuitivo. Nel frattempo, "avere un'idea originale" rimane nella mia lista dei secchi per un altro giorno.

+1

Non è questa tipizzazione essenzialmente strutturale (http://en.wikipedia.org/wiki/Structural_typing)? – Noldorin

+0

@Noldorin: Grazie, non sapevo che avesse un nome. Scansionando oltre, direi che sì, lo è. –

+1

@Jeff: Sì, ora sono abbastanza fiducioso che * sono * le stesse cose, anche se alcuni dei commenti sul post del blog di Jon Skeet lo descrivono come una digitazione anatra (che è sottilmente diversa dalla tipizzazione strutturale). Qualunque cosa sia, è un'idea molto carina ... forse qualcosa da desiderare in C# 5. :) – Noldorin

risposta

3

Penso che sia problematico. Stai introducendo l'accoppiamento tra due classi che non sono accoppiate.

Considerare il seguente codice.

public interface IFoo 
{ 
    int MethodA(); 
    int MethodB(); 
} 

public class Bar 
{ 
    int MethodA(); 
    int MethodB(); 
} 

public class SomeClass 
{ 
    int MethodFoo(IFoo someFoo); 
} 

dovrebbe essere legale?

int blah = someClass.MethodFoo((dynamic<IFoo>)bar); 

E sembra come dovrebbe essere legale, perché il compilatore dovrebbe essere in grado di digitare in modo dinamico bar come qualcosa che implementa IFoo.

Tuttavia, a questo punto si stanno combinando IFoo e Bar tramite una chiamata in una parte completamente separata del codice.

Se si modifica la barra perché non ha più bisogno di MethodB, improvvisamente someClass.MethodFood non funziona più, anche se Bar e IFoo non sono correlati.

Allo stesso modo, se si aggiunge MethodC() a IFoo, il codice si interromperà di nuovo, anche se IFoo e Bar sono apparentemente non correlati.

Il fatto è che, sebbene ciò sia utile in alcuni casi in cui vi sono delle somiglianze tra gli oggetti che non si controllano, esiste una ragione per cui le interfacce devono essere esplicitamente associate agli oggetti e il motivo è che il compilatore può garantire che l'oggetto lo implementa.

+1

Ma l'OP dice esplicitamente contrassegnandolo come * dinamico * .Questo rompe la coerenza. Dynamic o = new object(); o.InvalidMethod(); dovrebbe anche fare. –

+0

Nell'uso del tag dinamico, stai semplicemente evidenziando il fatto che dovresti accoppiare gli oggetti Perché creare un tag dinamico speciale, quando si utilizza la "metodologia dell'interfaccia" già esistente? Forse potresti chiarire il tuo commento, non sono sicuro di averlo capito – DevinB

+0

L'esempio che hai dato non è corretto in quanto non si richiede esplicitamente digitando dinamicamente. Richiedo esplicitamente la digitazione dinamica, che, se entrambi i tipi sono noti in fase di compilazione, il compilatore può utilizzare per segnalare un errore di mancata corrispondenza di tipo o se in fase di esecuzione il DLR può determinare se le chiamate esistono, come deve fare per le singole chiamate già presenti nel meccanismo di tipo dinamico esistente di C# 4. –

1

Non è necessario che C# supporti questo, in quanto può essere implementato in modo molto pulito come libreria.

Ho visto tre o quattro implementazioni separate (ho iniziato a scriverne una prima di trovarle). Ecco il trattamento più completo che ho visto:

http://bartdesmet.net/blogs/bart/archive/2008/11/10/introducing-the-c-ducktaper-bridging-the-dynamic-world-with-the-static-world.aspx

Probabilmente sarà ancora più facile da implementare una volta che il DLR è integrato nella fase di esecuzione.

Poiché la classe wrapper/forwarder per una determinata interfaccia può essere generata una volta e quindi memorizzata nella cache, e quindi un determinato oggetto di tipo sconosciuto può essere spostato una volta, c'è molto spazio per la memorizzazione nella cache dei siti di chiamata, ecc. la performance dovrebbe essere eccellente. Al contrario, penso che la parola chiave dynamic, che è una caratteristica del linguaggio e molto complessa, sia una digressione inutile e potenzialmente disastrosa, con un linguaggio che in precedenza aveva una filosofia di tipizzazione statica molto chiara, che ha dato una direzione ovvia per il miglioramento futuro. Dovrebbero essersi attenuti a questo e hanno reso l'inferenza di tipo funzionante sempre meglio fino a quando la digitazione è diventata più invisibile. Ci sono così tante aree in cui potrebbero evolvere la lingua, senza rompere i programmi esistenti, eppure non lo fanno, semplicemente a causa di limiti di risorse (ad esempio il motivo var non può essere utilizzato in più posti è perché dovrebbero riscrivere il compilatore e non hanno tempo).

Stanno ancora facendo cose buone in C# 4.0 (le caratteristiche della varianza) ma c'è molto altro che potrebbe essere fatto per rendere il sistema di tipi più intelligente, più automatico, più potente nel rilevare i problemi in fase di compilazione. Invece, stiamo essenzialmente ottenendo un espediente.

+0

Penso che le motivazioni per includere la parola chiave dinamica siano più che accettabili considerando l'inferno che è l'interoperabilità in questo momento. Usando la parola chiave dinamica, mantiene la natura tipizzata staticamente del linguaggio e costringe gli sviluppatori a pensare a ciò che stanno scrivendo e ad essere impliciti nel loro uso di tipi dinamici - al contrario, usando la parola chiave oggetto per oggetti digitati dinamicamente. Penso che rendere invisibile la digitazione sia esattamente ciò che non si vuole in un linguaggio tipizzato staticamente. (var in più punti è più di una riscrittura del compilatore, è possibile una semantica del linguaggio ... –

+0

... cambia come dovresti includere le regole su chi arriva ad assegnare una variabile prima (in modo che il tipo possa essere correttamente dedotto) .Certamente non vedo dinamicamente come un espediente - è un enorme passo avanti per cose come l'interoperabilità COM e un bel modo di fornire supporto linguistico dinamico in un linguaggio tipizzato staticamente.Il compilatore fa enormi quantità di lavoro per quanto riguarda l'uso del tipo ma non sono sicuro che fare di più sia una buona idea in quanto può portare a un pigro sviluppo di codice errato. Il compilatore dovrebbe imporre regole, non fornirci modi per ignorarle. –

+0

È un modo _one_ di fornire un supporto dinamico alla lingua in un linguaggio tipizzato staticamente, a mio avviso (già spiegato) è quello sbagliato Re: applicare le regole, sto solo parlando del tipo di inferenza fatta da linguaggi come Haskell, le regole sono applicate e quindi non possono essere ignorate. il nee d dire la stessa cosa * due volte * è ridotta. Deve essere una buona cosa. –

1

Il framework opensource Impromptu-Interface utilizza il C# 4 e il dlr.

using ImpromptuInterface; 

interface IMyInterface 
{ 
    bool Visible 
    { 
     get; 
    } 
} 

TextBox myTextBox = new TextBox(); 
IMyInterface i = myTextBox.ActLike<IMyInterface>(); 

Poiché utilizza il dlr, funzionerà anche con ExpandoObject e DynamicObject.

+0

Com'è diverso dal semplice esibire un cast? Il mio suggerimento originale era una convenienza sul lato dello sviluppo che non ha alcun impatto sul runtime. –

+0

Questo è il mio punto non è diverso - solo che funziona ora con il runtime come è oggi con una sintassi leggermente diversa.Il costo di runtime è minimo genera un proxy molto leggero che viene memorizzato nella cache se si guarda solo al costo di chiamata esplicita è 1 chiamata statica + 1 chiamata DLR. – jbtule