2009-06-11 20 views
47

Estoy en una situación en la que me gustaría crear una instancia de un objeto de un tipo que se determinará en tiempo de ejecución. También necesito realizar un lanzamiento explícito a ese tipo.Crear una instancia de un objeto con un tipo determinado en el tiempo de ejecución

Algo como esto:

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

Esto obviamente no es un código válido, pero espero que transmite la esencia de lo que estoy tratando de hacer. El método en el que estoy trabajando tendrá que realizar la operación de cálculo de referencias en ~ 35 tipos diferentes. Tengo varios otros métodos que deberán hacer algo similar con el mismo conjunto de tipos. Por lo tanto, me gustaría aislar la lógica de determinación del tipo de estos métodos para que solo tenga que escribirla una vez, y para que los métodos se mantengan limpios y legibles.

Debo admitir que soy un principiante total en el diseño. ¿Alguien podría sugerir un buen enfoque para este problema? Sospecho que podría haber un patrón de diseño apropiado que desconozco.

+1

Tal http://msdn.microsoft.com/en- us/library/system.activator.aspx puede ayudarlo?A menudo es útil para crear instancias de objetos cuyo tipo solo conoce en tiempo de ejecución. Se puede hacer con Reflection regular pero es un poco más complicado. No tengo ideas sobre su diseño, así que no responderé. – Skurmedel

+1

posible duplicado de [Obtener una nueva instancia de objeto de un Tipo] (http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type) – nawfal

Respuesta

97

Hay varias maneras de crear un objeto de un tipo determinado sobre la marcha, uno es:

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

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

y obtendrá una instancia de MyClass en obj.

Otra forma es utilizar la reflexión:

// 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[] { }); 

Y a partir de uno de ConstructorInfo regresó, se puede "Invoke()" con argumentos y volver una instancia de la clase como si usted ha usado una operador "nuevo".

+12

Esto no responde la pregunta (por completo). Él no sabe en tiempo de compilación si será 'MyClass' o' HisClass' o 'HerClass' (tipo determinado por el tiempo de ejecución). – Bitterblue

+4

@ mini-me Tenga en cuenta que en la pregunta el OP incluyó 'Escriba structType = getTypeFromEnum (val);'. Solo estoy agregando un código de ejemplo para demostrar que uno debe obtener la instancia 'Type' primero. – chakrit

+0

No estoy seguro de si tienes eso: critiqué la parte del elenco de tu respuesta. La respuesta de Rex M da una solución de trabajo completa + referencias de otra manera usando dinámica. – Bitterblue

9

creo que estás buscando Activator.CreateInstance

+1

Sí, lo hice también. Usé esto para ayudar. http://stackoverflow.com/questions/752/get-a-new-object-instance-from-a-type-in-c –

10

Puede en su mayoría hacer lo que está describiendo, pero ya que no conoce el tipo en tiempo de compilación, tendrá que mantener la instancia sin mecanografiar; comprobar su tipo en cada punto que lo utilice, y echarlo apropiada a continuación (esto no será necesario con C# 4.0, que soporta dynamics):

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

... 


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

Creación de una instancia de un tiempo de ejecución determinado Type es fácil, usando Activator.CreateInstance, como otros han mencionado. Sin embargo, no es posible enviarlo, como lo hace en su ejemplo en la línea Marshal.PtrToStructure, ya que el tipo debe conocerse en el momento de la compilación para la conversión. Además, tenga en cuenta que Activator.CreateInstance no se puede utilizar junto con un IntPtr.

Si sus tipos tienen una clase base común (distinta de Object), puede convertirla a dicho tipo de base y llamar a funciones sobre eso. De lo contrario, las funciones de llamada solo serán posibles mediante la reflexión.

Así que o bien:

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

O:

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..); 
} 
+0

+1. La idea más útil de @Aistina es definir una clase base o interfaz y hacer todo lo que se necesite contra eso en lugar de simplemente crear una instancia de un tipo determinado en tiempo de ejecución – Evan

0

Usted podría ir dinámica:

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; } 
     } 
    } 
} 
-2
methodName = NwSheet.Cells[rCnt1, cCnt1 - 2].Value2; 
          Type nameSpace=typeof(ReadExcel); 
          Type metdType = Type.GetType(nameSpace.Namespace + "." + methodName); 
          //ConstructorInfo magicConstructor = metdType.GetConstructor(Type.EmptyTypes); 
          //object magicClassObject = magicConstructor.Invoke(new object[] { }); 
          object magicClassObject = Activator.CreateInstance(metdType); 
          MethodInfo mthInfo = metdType.GetMethod("fn_"+methodName); 
          StaticVariable.dtReadData.Clear(); 
          for (iCnt = cCnt1 + 4; iCnt <= ShtRange.Columns.Count; iCnt++) 
          { 
           temp = NwSheet.Cells[1, iCnt].Value2; 
           StaticVariable.dtReadData.Add(temp.Trim(), Convert.ToString(NwSheet.Cells[rCnt1, iCnt].Value2)); 
          } 


          //if (Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_AddNum" || Convert.ToString(NwSheet.Cells[rCnt1, cCnt1 - 2].Value2) == "fn_SubNum") 
          //{ 
          // //StaticVariable.intParam1 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 4].Value2); 
          // //StaticVariable.intParam2 = Convert.ToInt32(NwSheet.Cells[rCnt1, cCnt1 + 5].Value2); 
          // object[] mParam1 = new object[] { Convert.ToInt32(StaticVariable.dtReadData["InParam1"]), Convert.ToInt32(StaticVariable.dtReadData["InParam2"]) }; 
          // object result = mthInfo.Invoke(this, mParam1); 
          // StaticVariable.intOutParam1 = Convert.ToInt32(result); 
          // NwSheet.Cells[rCnt1, cCnt1 + 2].Value2 = Convert.ToString(StaticVariable.intOutParam1) != "" ? Convert.ToString(StaticVariable.intOutParam1) : String.Empty; 
          //} 

          //else 
          //{ 
           object[] mParam = new object[] { }; 
           mthInfo.Invoke(magicClassObject, mParam); 
Cuestiones relacionadas