2009-01-21 6 views
17

C'est ce que je dois faire:Est-il possible de convertir une variable en type stocké dans une autre variable?

object foo = GetFoo(); 
Type t = typeof(BarType); 
(foo as t).FunctionThatExistsInBarType(); 

Peut-être quelque chose comme ça fait?

+0

Comment savez-vous que c'est une chaîne que vous voulez sur le côté gauche des égaux dans la dernière ligne votre exemple? En d'autres termes, qu'allez-vous faire avec la barre, ce qui signifie que vous ne pouvez pas utiliser "object bar = (object) foo;" ? –

+0

Je ne fais pas, la chaîne était seulement un exemple. J'ai modifié l'extrait. –

Répondre

13

Non, vous ne pouvez pas. C# n'implémente pas duck typing.

Vous devez implémenter une interface et lancer la conversion.

(Cependant, il y a des tentatives de le faire. Regardez Duck Typing Project un exemple.)

+0

Oui, vous pouvez. Regardez la réponse de GvS :-) –

+1

Vous devez toujours implémenter l'interface (IConvertible dans ce cas), et connaître le type à lancer à l'avance. – Quassnoi

+0

J'ai marqué cette réponse comme une réponse acceptée, car j'ai utilisé les conseils de Quassnoi et mis en place une interface pour y répondre, mais les réponses de GvS et de shuggycouk sont également excellentes. –

20

Vous pouvez utiliser la méthode Convert.ChangeType.

object foo = GetFoo(); 
Type t = typeof(string); 
string bar = (string)Convert.ChangeType(foo, t); 
+6

Ceci n'est utile que si l'objet implémente IConvertible – Quassnoi

+4

J'ai utilisé une chaîne uniquement à titre d'exemple. Le problème est que je ne connais pas le type de cible, donc je ne peux pas exécuter cette barre xyz = (xyz) Convert.Change ... cast. –

+0

Convert.ChangeType n'est pas en cours de conversion, il est en cours de conversion. c'est-à-dire créer un nouvel objet du type spécifié. Si vous voulez lancer ICollection, cela ne fonctionnera pas. – Hoots

4

Votre question était entachée d'erreurs dans ce que vous demandez de traiter une variable comme un type qui ne sait pas au moment de la compilation, mais notez que vous avez chaîne définie sur le côté gauche lorsque vous déclarez votre variable. C# à partir de 3.5 est typé statiquement.

vous pourriez Une fois dynamique est disponible faire quelque chose comme ceci:

dynamic foo = GetFoo(); 
foo.FunctionThatExistsInBarType(); 

lorsque vous ne savez pas ce que le type est mais vous savez qu'il soutiendra toujours la méthode d'instance FunctionThatExistsInBarType(); Pour l'instant vous êtes obligé d'utiliser la réflexion (ou le code gen qui revient à peu près la même chose mais plus cher à l'avant et plus vite plus tard).

// any of these can be determined at runtime 
Type t = typeof(Bar); 
string methodToCall = "FunctionThatExistsInBarType"; 
Type[] argumentTypes = new Type[0]; 
object[] arguments = new object[0]; 
object foo; 
// invoke the method - 
// example ignores overloading and exception handling for brevity 
// assumption: return type is void or you don't care about it 
t.GetMethod(methodToCall, BindingFalgs.Public | BindingFlags.Instance) 
    .Invoke(foo, arguments); 
+1

Le type de chaîne était seulement un exemple (pas un bon); J'ai édité l'extrait de code, j'espère que c'est plus clair maintenant. –

+0

Droit - pour cela (pré dynamique), vous devez utiliser la réflexion. Je vais modifier pour prendre cela en compte – ShuggyCoUk

0

A condition que vous connaissez tous les types nécessaires à la compilation, duck typing est (un peu) possible:

class BarFoo {} 
class Foo {} 
class Bar {} 

class Program 
{ 
    static void Main() 
    { 
     var foo = new Foo(); 
     var bar = new Bar(); 
     var barfoo = new BarFoo(); 

     Console.WriteLine(DoStuff(foo)); 
     Console.WriteLine(DoStuff(bar)); 
     Console.WriteLine(DoStuff(barfoo)); 

    } 

    static string DoStuff(Foo foo) { return "DoStuff(Foo foo)"; } 
    static string DoStuff(Bar bar) { return "DoStuff(Bar bar)"; } 
    static string DoStuff(Base fb) { return "DoStuff(object fb)"; } 
} 

Sortie:

Dostuff(Foo foo) 
Dostuff(Bar bar); 
DoStuff(object fb); 

Si vous finissez par mettre en œuvre un grand nombre de méthodes qui font exactement la même chose, envisager d'implémenter une interface.

+0

Euh .. Quatre ans plus tard .. Oh bien. –

+2

Ce n'est pas un typage de canard. C'est un polymorphisme (appliqué à la fonction 'DoStuff'). –

2

Depuis la dynamique ont été ajoutés à C#, je pense que nous pouvons le faire de cette façon:

class Program { 
    static void Main(string[] args) { 
     List<int> c = new List<int>(); 
     double i = 10.0; 
     Type intType = typeof(int); 
     c.Add(CastHelper.Cast(i, intType)); // works, no exception! 
    } 
} 

class CastHelper { 
    public static dynamic Cast(object src, Type t) { 
     var castMethod = typeof(CastHelper).GetMethod("CastGeneric").MakeGenericMethod(t); 
     return castMethod.Invoke(null, new[] { src }); 
    } 
    public static T CastGeneric<T>(object src) { 
     return (T)Convert.ChangeType(src, typeof(T)); 
    } 
} 
+1

Cela a fonctionné comme un charme où d'autres solutions n'ont pas. – BrotherOdin

+0

Parfait, merci! – Stark

Questions connexes