web-dev-qa-db-fra.com

Cast vers un type reflété en C #

Considérons le code suivant: 

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;

Dois-je faire de la magie avec typeFoo pour obtenir le résultat?

16
user2341923

Non :-)

Cas 1:

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

Aucune réflexion ici, car vous connaissez le type Foo au moment de la compilation.

Cas 2: interfaces. Normalement, le meilleur ... Vous ne savez pas ce que renvoie exactement MakeFoo, mais vous savez que c'est une interface IFoo ...

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

Cas 3: vous n'êtes pas sûr que MakeFoo renvoie Foo

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

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

ou similaire

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

Foo foo = objFoo as Foo;

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

Cas 4: type Foo est complètement inconnu de votre programme. Vous n'avez pas de classe Foo référençable ...

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!

la dynamic utilise en interne la réflexion. Vous pouvez utiliser la réflexion directement pour obtenir la méthode Quack et l'appeler

Cas 5: en tant que cas 4, mais en utilisant directement la réflexion:

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 });

ou, avec quelques vérifications, si vous n'êtes pas sûr, foo peut Quack correctement:

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 });
}

Case -Infinity: type Foo est complètement inconnu de votre programme. Vous n'avez pas de classe Foo référençable. Vous n'avez pas d'interface IFoo. Vous ne savez même pas ce qu'est une Foo, vous savez seulement que c'est une classe (ou peut-être que c'est une struct encadrée, mais cela ne change pas de votre point de vue ... Ça ne peut pas être une interface car fin il doit toujours y avoir une class/struct derrière chaque interface). Vous ne connaissez pas ses méthodes, ses champs, ses propriétés (car vous ne savez pas ce que est Foo).

Même si vous pouvez lancer une object dans cette classe inconnue, que pouvez-vous faire? Vous ne pouvez pas avoir de méthodes dans votre code qui l'acceptent comme paramètre/valeur de retour, car si vous aviez quelque part:

int INeedFoo(Foo par) { return 0; }

alors clairement vous sauriez Foo. La bibliothèque .NET ne peut pas avoir de méthodes qui l'acceptent comme paramètre/valeur de retour, car si c'était le cas, vous devriez connaître Foo

La seule chose que vous puissiez faire est de le transmettre à d'autres méthodes découvertes par réflexion qui acceptent Foo en tant que paramètre ... Mais la méthode Invoke accepte un tableau de object en tant que paramètres ... Vous n'avez pas besoin de convertir votre object. appeler Invoke! Il vous suffit de le mettre dans le tableau.

52
xanatos

Cela équivaudrait à:

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

Il est inutile de convertir un objet en un type inconnu au moment de la compilation - vous ne pourrez pas l'utiliser:

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

Puisque vous ne savez pas ce que UknownType est, vous ne pourrez utiliser aucune de ses méthodes sans recourir à la réflexion ou à la dynamique.

1
zmbq