web-dev-qa-db-ja.com

実行時決定型でオブジェクトをインスタンス化する

実行時に決定されるタイプのオブジェクトをインスタンス化したい状況にいます。また、その型への明示的なキャストを実行する必要があります。

このようなもの:

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種類のマーシャリング操作を実行する必要があります。同じタイプのセットで同様のことを行う必要がある他のいくつかのメソッドがあります。そこで、これらのメソッドから型決定ロジックを分離して、一度だけ記述するだけで済み、メソッドがクリーンで読みやすい状態に保たれるようにします。

私は設計の完全な初心者であることを認めなければなりません。誰もこの問題への良いアプローチを提案できますか?気付いていない適切なデザインパターンがあるのではないかと思います。

59
Odrade

特定のタイプのオブジェクトをその場で作成できる方法はいくつかあります。1つは次のとおりです。

// 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の1つから、引数を使用して「Invoke()」し、「新しい」演算子を使用したかのようにクラスのインスタンスを取得できます。

116
chakrit

あなたは大部分あなたが記述していることをすることができますが、コンパイル時に型がわからないので、インスタンスを保持する必要があります緩く型付けされた;使用する各ポイントでそのタイプを確認し、適切にキャストします(これは 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;
}
14
Rex M

Activator.CreateInstanceを探していると思います

10
Jason Punyon

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

あなたは動的に行くことができます:

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; }
        }
    }
}
1
Jakob Flygare