2 votes

Passage de type dynamique et instanciation -- comment ?

EDIT : modifié Activator mais cela ne fonctionne toujours pas.

Je suis assez (très) novice en C# et je suis presque sûr que c'est un doublon, mais j'ai regardé les questions précédentes et je n'arrive toujours pas à comprendre tous les points.

J'essaie de réduire l'odeur du code en remplaçant une partie du code répété par une carte sur une liste générique. Plus précisément, j'ai un code qui ressemble à

var fooNode = node as IFoo;
var barNode = node as IBar;
var bazNode = node as IBaz;
...

if(fooNode != null)
    return new FooThing();
if(barNode != null)
    return new BarThing();
if(bazNode != null)
    return new BazThing();
...

et je veux la généraliser.


Voici ma tentative :

var types = new Dictionary<Type, Type>
{
    {typeof(IFoo), typeof(FooThing)},
    {typeof(IBar), typeof(BarThing)},
    ...
}

foreach(var entry in types)
{
    var castNode = node as entry.Key;
    return Activator.CreateInstance(entry.Value);
}

Naturellement, cela ne fonctionne pas : The type or namespace name 'entry' could not be found (are you missing a using directive or an assembly reference?) . Pouvez-vous nous aider ? Ce genre de chose est-il possible en C# ?

3voto

Justin Points 42106

Que pensez-vous de ceci ?

foreach(var entry in types)
{
    if (node != null && entry.Key.IsAssignableFrom(node.GetType()))
    {
        return Activator.CreateInstance(entry.Value);
    }
}

Le problème est que vous confondez les paramètres des types génériques avec les types d'exécution, et en particulier le paramètre Type classe.

Si vous savez ce que sera un type au moment de la compilation, vous pouvez utiliser la fonction générique Activator.CreateInstance<T>() pour créer une instance de l'objet sous-jacent - vous pouvez utiliser des paramètres de type pour que cette ligne de code n'ait pas besoin de connaître le type de l'objet, par exemple :

T CreateObject<T>()
{
    return Activator.CreateInstance<T>();
}

Cependant, cela ne fait que passer la main. Pour appeler cette méthode, la valeur du paramètre de type T doit être fourni quelque part - Dans les deux cas, le compilateur doit être en mesure de résoudre les problèmes suivants T à un type (plutôt qu'à une variable ou à une méthode).

Inversement, le Type codifie les informations sur le type au niveau de durée d'exécution comme son nom ou l'assemblage dans lequel un type est déclaré. Activator.CreateInstance dispose également d'une surcharge qui vous permet de fournir une instance de Type :

object CreateObject(Type type)
{
    return Activator.CreateInstance(type);
}

Dans votre cas, il semble que vous ne sachiez pas quels seront les types au moment de la compilation. Type vous pouvez utiliser typeof(MyClass) pour obtenir une instance de l'élément Type pour une classe connue au moment de l'exécution, et myObject.GetType() pour obtenir des informations sur le type d'un objet au moment de l'exécution.

2voto

Akash Kava Points 18026
var types = new Dictionary<Type, Type>
{
    {typeof(IFoo), typeof(FooThing)},
    {typeof(IBar), typeof(BarThing)},
    ...
}

foreach(var entry in types)
{
    if(entry.Key.IsAssignableFrom(node.GetType()))
       return Activator.CreateInstance(entry.Value);
}

return null;

0voto

Garvin Points 357

Il sera difficile de vous aider si vous ne comprenez pas clairement la raison pour laquelle vous souhaitez renvoyer des types différents à partir de la même opération. Peut-être un peu d'information sur le problème que vous essayez de résoudre ?

Je suppose que, puisque vous essayez de les renvoyer de manière interchangeable, fooThing, BartThing et BazThing ont la même interface. Je suppose donc ce qui suit :

 public class FooThing : IMyOperations
 {

 }

 public class BarThing : IMyOperations
 {

 }

 public class BazThing : IMyOperations
 {

 }

Vous pouvez définir la relation entre les classes dans une autre interface

 public interface IMyChoice
 {
      public bool IsSelected { get; }
      public IMyOperations GetWorker();
 } 

 public class ChoiceFoo : IMyChoice
 {

 }

 public class ChoiceBar : IMyChoice
 {

 }

 public class ChoiceBaz : IMyChoice
 {

 }

Vous pouvez maintenant dire

 foreach( var entry in choices)
 {
    if(entry.IsSelected)
    {
         return entry.GetWorker();
         //Can't remember if i need to break after return..doubt it
    }
 }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X