views:

2050

answers:

4

I'm in a situation where I'd like to instantiate an object of a type that will be determined at runtime. I also need to perform an explicit cast to that type.

Something like:

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

This is obviously not valid code, but I hope it conveys the essence of what I'm trying to do. The method I'm actually working on will have to perform the marshaling operation on ~35 different types. I have several other methods that will need to do something similar with the same set of types. So, I'd like to isolate the type-determining logic from these methods so that I only need to write it once, and so that the methods stay clean and readable.

I must admit to being a total novice at design. Could anyone suggest a good approach to this problem? I suspect there might be an appropriate design pattern that I'm unaware of.

+3  A: 

I think you're looking for Activator.CreateInstance

Jason Punyon
+8  A: 

There are several ways you can create an object of a certain type on the fly, one is:

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

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

And you'll get an instance of MyClass in obj.

Another way is to use reflection:

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

And from one of ConstructorInfo returned, you can "Invoke()" it with arguments and get back an instance of the class as if you've used a "new" operator.

chakrit
+1  A: 

You can mostly do what you're describing, but since you don't know the type at compile-time, you'll have to keep the instance loosely-typed; check its type at each point you use it, and cast it appropriately then (this will not be necessary with c# 4.0, which supports dynamics):

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

...


if(obj is MyCustomType)
{
    ((MyCustomType)obj).Property1;
}
else if (obj is MyOtherCustomType)
{
    ((MyOtherCustomType)obj).Property2;
}
Rex M
+2  A: 

Creating an instance of a run-time determined Type is easy, using Activator.CreateInstance, as others have mentioned. However, casting it, as you do in your example on the Marshal.PtrToStructure line is not possible, as the type has to be known at compile time for casting. Also, note that Activator.CreateInstance can not be used in conjunction with an IntPtr.

If your types have a common base class (other than Object), you can cast it to said base type and call functions on that. Otherwise, calling functions will only be possible using reflection.

So either:

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

Or:

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..);
}
Aistina
+1. @Aistina's more useful idea is to define a base class or interface and do whatever work is needed against that rather than just creating an instance of a run-time determined type
Evan