60 votes

Instancier un objet avec un type déterminé à l'exécution

Je suis dans une situation où je voudrais instancier un objet d'un type qui sera déterminé au moment de l'exécution. J'ai aussi besoin d'effectuer un cast explicite de ce type.

Quelque chose comme ceci:

static void castTest(myEnum val)
{
    //Call a native function that returns a pointer to a structure
    IntPtr = someNativeFunction(..params..);

    //determine the type of the structure based on the enum value
    Type structType = getTypeFromEnum(val);

    structType myStruct = (structType)Marshal.PtrToStructure(IntPtr, structType);
}

Ce n'est évidemment pas un code valide, mais j'espère qu'il traduit l'essence même de ce que je suis en train de faire. La méthode que je suis en train de travailler sur aurez à effectuer l'opération de regroupement sur ~35 différents types. J'ai plusieurs autres méthodes qui devront faire quelque chose de similaire avec le même ensemble de types. Donc, j'aimerais isoler le type de détermination logique de ces méthodes, de sorte que je n'ai besoin de l'écrire une fois, et donc que les méthodes rester propre et lisible.

Je dois avouer être un novice total lors de la conception. Quelqu'un peut-il suggérer une bonne approche de ce problème? Je présume qu'il pourrait être un motif de conception que je suis pas au courant de.

119voto

chakrit Points 29562

Il existe plusieurs façons de créer un objet d'un certain type à la volée. L'une d'elles est:

 // determine type here
var type = typeof(MyClass);

// create an object of the type
var obj = (MyClass)Activator.CreateInstance(type);
 

Et vous obtiendrez une instance de MyClass dans obj.

Une autre façon consiste à utiliser la réflexion:

 // get type information
var type = typeof(MyClass);

// get public constructors
var ctors = type.GetConstructors(BindingFlags.Public);

// invoke the first public constructor with no parameters.
var obj = ctors[0].Invoke(new object[] { });
 

Et à partir de l'un des ConstructorInfo renvoyés, vous pouvez "Invoke ()" avec des arguments et récupérer une instance de la classe comme si vous utilisiez un "nouvel" opérateur.

15voto

Rex M Points 80372

Vous pouvez faire la plupart du temps ce que vous décrivez, mais comme vous ne connaissez pas le type au moment de la compilation, vous devez conserver l'instance typée de manière lâche; vérifiez son type à chaque fois que vous l'utilisez, puis lancez-le correctement (cela ne sera pas nécessaire avec c # 4.0, qui prend en charge la dynamique ):

 Type type = CustomGetTypeMethod();
var obj = Activator.CreateInstance(type);

...


if(obj is MyCustomType)
{
    ((MyCustomType)obj).Property1;
}
else if (obj is MyOtherCustomType)
{
    ((MyOtherCustomType)obj).Property2;
}
 

10voto

Jason Punyon Points 21244

Je pense que vous cherchez Activator.CreateInstance

6voto

Aistina Points 6720

La création d'une instance d'un temps déterminé Type est facile, à l'aide de Activator.CreateInstance, comme d'autres l'ont mentionné. Cependant, moulage, comme vous le faites dans votre exemple sur l' Marshal.PtrToStructure ligne n'est pas possible, que le type doit être connu au moment de la compilation pour la coulée. Notez également que, Activator.CreateInstance ne peut pas être utilisé en conjonction avec un IntPtr.

Si vos types ont une classe de base commune (autres que Object), vous pouvez le convertir en dit un type de base et les fonctions d'appel sur ce point. Sinon, appeler des fonctions ne sera possible qu'à l'aide de la réflexion.

Donc, soit:

static void castTest(myEnum val)
{
  //Call a native function that returns a pointer to a structure
  IntPtr val = someNativeFunction(..params..);

  //determine the type of the structure based on the enum value
  Type structType = getTypeFromEnum(val);

  BaseClass myStruct = (BaseClass)Marshal.PtrToStructure(IntPtr, structType);
  myStruct.SomeFunctionDeclaredInBaseClass();
}

Ou:

static void castTest(myEnum val)
{
  //Call a native function that returns a pointer to a structure
  IntPtr val = someNativeFunction(..params..);

  //determine the type of the structure based on the enum value
  Type structType = getTypeFromEnum(val);

  object myStruct = Marshal.PtrToStructure(IntPtr, structType);
  MemberInfo[] function = FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
    (MemberFilter)delegate(MemberInfo info, object filter)
    {
      return info.Name == filter.ToString();
    }, "SomeFunction");
  if (mi.Length > 0 && mi[0] is MethodInfo)
    ((MethodInfo)mi[0]).Invoke(myStruct, ..params..);
}

1voto

Jakob Flygare Points 71

Vous pouvez aller dynamique:

 using System;

namespace TypeCaster
{
    class Program
    {
        internal static void Main(string[] args)
        {
            Parent p = new Parent() { name = "I am the parent", type = "TypeCaster.ChildA" };
            dynamic a = Convert.ChangeType(new ChildA(p.name), Type.GetType(p.type));
            Console.WriteLine(a.Name);

            p.type = "TypeCaster.ChildB";
            dynamic b = Convert.ChangeType(new ChildB(p.name), Type.GetType(p.type));
            Console.WriteLine(b.Name);
        }
    }

    internal class Parent
    {
        internal string type { get; set; }
        internal string name { get; set; }

        internal Parent() { }
    }

    internal class ChildA : Parent
    {
        internal ChildA(string name)
        {
            base.name = name + " in A";
        }

        public string Name
        {
            get { return base.name; }
        }
    }

    internal class ChildB : Parent
    {
        internal ChildB(string name)
        {
            base.name = name + " in B";
        }

        public string Name
        {
            get { return base.name; }
        }
    }
}
 

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