2010-08-16 15 views
19

Il seguente codice genera un'eccezione. TryConvert non viene chiamato per il cast da interfacciare. Perchè è questo? Posso aggirare il problema?DynamicObject.TryConvert non chiamato durante la trasmissione al tipo di interfaccia

using System.Dynamic; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      dynamic test = new JsonNull(); 
      var ok = (string)test; 
      // Next line throws: 
      // Unable to cast object of type 'ConsoleApplication1.JsonNull' to type 'ConsoleApplication1.IFoo'. 
      var fail = (IFoo)test; 
     } 
    } 

    class JsonNull : DynamicObject 
    { 
     public override bool TryConvert(ConvertBinder binder, out object result) 
     { 
      result = null; 
      return !binder.Type.IsValueType; 
     } 
    } 

    interface IFoo { } 
} 
+0

Che cosa dice la documentazione? E 'questo supportato? – leppie

+0

Avete mai trovato un modo per aggirare il problema? –

+0

No, mi dispiace, non l'ho fatto :( –

risposta

9

ho il sospetto che sia perché in C# (e possibilmente .NET in generale) non è possibile creare una conversione definito dall'utente a un tipo di interfaccia (nello stesso modo in cui non è possibile creare un definito dall'utente conversione in/da un tipo base/figlio). Pertanto, ogni conversione dell'interfaccia viene considerata come una scatola o una conversione di riferimento.

Che davvero è solo un'ipotesi però.

EDIT: D'altra parte, ho appena avuto uno sguardo al codice generato per:

e fa generare una chiamata dinamica tramite Binder.Convert, quindi non è il compilatore C# fare Questo. Hmm.

+0

Anche quello era il mio sospetto. Suppongo che il casting su un'interfaccia non sia inteso a restituire un'istanza di oggetto diversa, solo una vista diversa della stessa istanza. –

+0

@Andrew: Potresti voler * prova * implementando autonomamente 'IDynamicMetaObjectProvider'. Mi chiedo se sia arrivato così lontano. –

12

Ho scoperto che se si cambia questa linea:

var fail = (IFoo)test; 

a questo:

IFoo success = test; 

esso funziona come previsto.

Sembra che solo una conversione implicita funzioni in questo caso. Sembra un insetto per me.

anche io trovo molto fastidioso che questo non riesce così:

class Program { 
    static void Main(string[] args) { 
    dynamic test = new JsonNull(); 
    Fails(test); 
    } 
    static void Fails(IFoo ifoo) { } 
} 
// ... 

Perché sembra che dovrebbe utilizzare una conversione implicita troppo. Un altro bug?

+0

Funziona anche per i valori restituiti: 'IEnumerable SomeFunc() {dynamic x = ...; ritorno x; } 'chiama TryConvert sul mio oggetto dinamico –

6

Questo comportamento è spiegato nel post del blog On Dynamic Objects and DynamicObject da Chris Burrows:

"C'è un altro intoppo in DynamicObject (..) quando la lingua di base del sito chiamata fornisce alcune vincolante per qualsiasi operazione, che annulla vincolanti

(..) ricordare che esiste sempre una conversione esplicita dalla maggior parte dei tipi di classe a qualsiasi tipo di interfaccia in C# (6.2.4, punto 3), anche se possono fallire. (..)

Solo per espandere il esempio di conversione dell'interfaccia un po ', è particolarmente strano dal momento che se la conversione fosse implicita (diciamo, prova ad assegnare a un locale), allora la conversione dinamica avrebbe funzionato. Perché? Perché il raccoglitore C# avrebbe detto "no! nessuna conversione implicita a IEnumerable,”e poi l'attuazione DynamicObject avrebbero lasciato TryConvert fare il suo dovere."

Problemi correlati