【问题标题】:Instantiate an object with a runtime-determined type实例化具有运行时确定类型的对象
【发布时间】:2010-11-02 03:39:51
【问题描述】:

我想实例化一个类型的对象,该类型将在运行时确定。我还需要对该类型执行显式强制转换。

类似这样的:

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 种不同类型执行编组操作。我还有其他几种方法需要对同一组类型执行类似的操作。因此,我想将类型确定逻辑与这些方法隔离开来,这样我只需要编写一次,从而使方法保持干净和可读。

我必须承认自己是一个设计新手。任何人都可以提出解决这个问题的好方法吗?我怀疑可能存在我不知道的适当设计模式。

【问题讨论】:

标签: c# .net design-patterns runtime


【解决方案1】:
 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);

【讨论】:

    【解决方案2】:

    你可以动态:

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

    【讨论】:

      【解决方案3】:

      正如其他人所提到的,使用Activator.CreateInstance 创建运行时确定的Type 的实例很容易。但是,无法像在 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 更有用的想法是定义一个基类或接口并针对它做任何需要的工作,而不是仅仅创建一个运行时确定类型的实例
      【解决方案4】:

      有几种方法可以即时创建特定类型的对象,其中一种是:

      // 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”运算符一样。

      【讨论】:

      • 这并不能(完全)回答问题。他在编译时不知道是MyClass 还是HisClass 还是HerClass(运行时确定的类型)。
      • @mini-me 请注意,在问题中,OP 包含Type structType = getTypeFromEnum(val);。我只是添加一个示例代码来演示应该首先获取Type 实例。
      • 不确定你是否明白:我批评了你回答的演员部分。 Rex M 的答案给出了一个完整的工作解决方案 + 引用了另一种使用动力学的方法。
      • @mini-me 这只是一个例子。 OP 正在寻找一个 API 来执行此操作。代码足以回答。我无法按照 OP 想要的方式编译所有内容,这对 OP 并没有真正的帮助。和 IMO 实际上大多数时候你至少会知道并希望对象基于某些基本类型或接口,并且几乎总是永远不会完全动态或直接简单的Object,因为这些非常无用(或者不需要运行时反射使用。)
      • 我用inputObj.GetType()代替了typeof(MyClass)。这提供了类型,但可能不适用于强制转换。就我而言,我有一个合适的父母,足以铸造。
      【解决方案5】:

      您可以大部分执行您所描述的操作,但由于您在编译时不知道类型,因此您必须保持实例的松散类型;在你使用它的每一点检查它的类型,然后适当地转换它(这对于支持dynamics的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】:

        我认为您正在寻找 Activator.CreateInstance

        【讨论】:

        猜你喜欢
        • 2012-10-26
        • 1970-01-01
        • 2015-07-17
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        • 1970-01-01
        • 2010-12-17
        相关资源
        最近更新 更多