使用运行时确定的类型实例化对象


69

我处于一种情况下,我想实例化一个将在运行时确定的类型的对象。我还需要执行对该类型的显式转换。

像这样:

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

这显然不是有效的代码,但我希望它传达了我正在尝试做的本质。我实际上正在使用的方法将必须在约35种不同类型上执行封送处理操作。我还有其他几种方法需要对同一组类型执行类似的操作。因此,我想将类型确定逻辑与这些方法隔离开,这样我只需要编写一次即可,并使这些方法保持清晰易读。

我必须承认自己是设计的新手。谁能建议一个解决这个问题的好方法?我怀疑可能有一个我不知道的合适的设计模式。


1
也许msdn.microsoft.com/en-us/library/system.activator.aspx可以为您提供帮助?对于实例化仅在运行时才知道其类型的对象通常很有用。可以通过常规的反射来完成,但是有点麻烦。我对您的设计没有任何想法,所以我不会回答。
Skurmedel

Answers:


129

您可以通过多种方式动态创建某种类型的对象,一种是:

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

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

然后,您将在obj中获得MyClass的实例。

另一种方法是使用反射:

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

从返回的ConstructorInfo之一中,您可以使用参数对其进行“ Invoke()”,并获得该类的实例,就好像您使用的是“ new”运算符一样。


29
这不能完全回答问题。他在编译时不知道它将是MyClassorHisClass还是HerClass(运行时确定的类型)。
Bitterblue 2013年

4
@ mini-me请注意,问题包括OP Type structType = getTypeFromEnum(val);。我只是添加示例代码来说明应该Type首先获取实例。
chakrit

1
不知道您是否明白:我批评了您的答案的强制性部分。Rex M的答案提供了完整的解决方案+引用了另一种使用动力学的方法。
Bitterblue 2013年

2
@ mini-me仅仅是一个例子。OP正在寻找API来执行此操作。该代码足以回答。我无法以OP想要的方式来编译所有内容,而这并不能真正帮助OP。而IMO在大多数情况下,实际上,您至少会知道并希望该对象基于某些基本类型或接口,并且几乎永远不会完全动态化或仅Object直接简单地进行修改,因为它们几乎没有用处(或不需要使用运行时反射来使用) 。)
chakrit 2013年

2
而不是typeof(MyClass)我用过的inputObj.GetType()。这提供了类型,但可能不适用于投射。就我而言,我有一个合适的父母足以进行铸造。
Zarepheth 2013年

17

几乎可以执行您正在描述的事情,但是由于您在编译时不知道类型,因此必须使实例保持松散类型。在使用它的每个点检查它的类型,然后进行适当的转换(对于支持dynamic的c#4.0则不需要这样做):

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

...


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


6

就像其他人提到的那样Type,使用创建一个确定的运行时实例很容易Activator.CreateInstance。但是,无法像在示例中那样在Marshal.PtrToStructure网上进行转换,因为在编译时必须知道类型。另外请注意Activator.CreateInstance不能与IntPtr一起使用。

如果您的类型具有共同的基类(除 Object),则可以将其强制转换为所述基本类型并在其上调用函数。否则,只能使用反射来调用函数。

所以:

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

要么:

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

+1。@Aistina的更有用的想法是定义一个基类或接口,并为此做任何必要的工作,而不仅仅是创建运行时确定类型的实例
Evan,2010年

1

您可以动态化:

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

-6
 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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.