2013-08-05 12 views
13

Si consideri il seguente codice:Fusioni a un riflesso tipo in C#

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 
MethodInfo methodInfo = typeof(Program).GetMethod("Baz"); // Foo Baz(){return foo;} 
Type typeFoo = methodInfo.ReturnType; 
var result = (typeFoo)objFoo; 

Ho bisogno di fare un po 'di magia con typeFoo per ottenere il risultato?

+0

Puoi spiegare cosa stai cercando di fare, dopo "risultato Foo"? –

+0

Nel codice originale è qualcosa come MethodInfo methodInfo = ... typeFoo = methodInfo.ReturnType; Quindi non so quale tipo sarà. – user2341923

+1

Se non sai di che tipo sarà, come si dichiara la variabile sul lato sinistro? –

risposta

49

No :-)

Caso 1:

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 
Foo result = (Foo)objFoo; 

Non v'è alcun riflesso qui, perché si conosce il tipo Foo in fase di compilazione.

Caso 2: interfacce. Normalmente il migliore ... Non sai che cosa esattamente MakeFoo ritorni, ma si sa che è un'interfaccia IFoo ...

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 
IFoo result = (IFoo)objFoo; 

Caso 3: non si è sicuri MakeFoo rendimenti Foo

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 

if (objFoo is Foo) 
{ 
    Foo result = (Foo)objFoo; 
} 

o, simile

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 

Foo foo = objFoo as Foo; 

if (foo != null) 
{ 
    // use foo 
} 

Caso 4: tipo Foo è completamente sconosciuto al tuo programma. Non si dispone di una classe Foo referenziabile ...

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 
Type typeFoo = objFoo.GetType(); // You should check for null values before! 

// and now? 

dynamic foo = objFoo; 

// because you know that foo can Quack(1, 2, 3)! 
string result = foo.Quack(1, 2, 3); 

// note that it will explode with a RuntimeBinderException if there is no 
// string Quack(int, int, int) method! 

il dynamic usa internamente riflessione. Si potrebbe utilizzare la reflection direttamente per ottenere il metodo Quack e chiamarlo

Caso 5: come caso 4, ma utilizzando direttamente riflessione:

object objFoo = MakeFoo(); // object MakeFoo(){return new Foo();} 
Type typeFoo = objFoo.GetType(); // You should check for null values before! 
MethodInfo mi = type.GetMethod("Quack"); // You should check if the Quack method 
             // exists 
string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 }); 

o, con alcuni controlli di integrità, se non si è assicurarsi foo può Quack correttamente:

MethodInfo mi = type.GetMethod("Quack", 
        BindingFlags.Instance | BindingFlags.Public, 
        null, 
        new[] { typeof(int), typeof(int), typeof(int) }, 
        null); 

if (mi != null && typeof(string).IsAssignableFrom(mi.ReturnType)) 
{ 
    string result = (string)mi.Invoke(objFoo, new object[] { 1, 2, 3 }); 
} 

caso -Infinity: tipo Foo è completamente sconosciuto a voi programma. Non hai una classe Foo referenziabile. Non hai un'interfaccia IFoo. Non sai nemmeno cosa sia uno , sai solo che è una classe (o forse è una scatola struct, ma non cambia dal tuo punto di vista ... Non può essere una interface perché nella alla fine deve esserci sempre un class/struct concreto dietro ogni interface). Non conosci i suoi metodi, i suoi campi, le sue proprietà (perché non sai cosa sia Foo).

Anche se è possibile trasmettere un valore object a questa classe sconosciuta, cosa si può fare?Non si può avere metodi nel codice che accettano come valore del parametro/ritorno, perché se da qualche parte si ha:

int INeedFoo(Foo par) { return 0; } 

allora è chiaro che si dovrebbe sapere di Foo. La libreria .NET non può avere metodi che lo accettano come parametro/valore di ritorno, perché se lo fosse, si saprebbe di Foo.

L'unica cosa che si può fare è passare ad alcuni altri metodi che si scoprono attraverso la riflessione che accettano Foo come parametro ... Ma il metodo Invoke accetta un array di object come parametri ... Non è necessario per trasmettere il tuo object per chiamare Invoke! Hai solo bisogno di metterlo nella matrice.

+0

Ho semplificato la domanda :-) – user2341923

+0

@XyiTebe Dimmi quale dei tre casi è quello che ti interessa – xanatos

+0

Il caso con dynamic è il più rilevante qui, anche se sarebbe bello sapere se riesco a trasmettere a un tipo che è noto in fase di runtime. – user2341923

1

Questo sarebbe equivalente a:

object objFoo = MakeFoo(); 
Foo result = (Foo)objFoo; 

Non c'è nessun vero e proprio punto di fusione di un oggetto a un tipo che si sa al momento della compilazione - non sarà in grado di usarlo:

object objFoo = MakeFoo(); 
UnkownType result = (UknownType)objFoo; 

Poiché non si sa cosa sia UknownType, non sarà possibile utilizzare nessuno dei suoi metodi senza ricorrere al riflesso o alla dinamica.

Problemi correlati