3

ジェネリッククラスを作成しましたが、設計ではなく実行時の型がわかるので、実行時に型を設定する方法を知りたいです。

たとえば、私は持っています:

public class MyGenericClass<T>
{
....
}

それから私はそれを使用しようとします。このジェネリック クラスを使用する他のクラスのメソッドがあります。このクラスのコンストラクターでは、必要な型をパラメーターとして受け取るため、必要な型を保存する型プロパティがあります。だから私はこれを試しています:

MyGenericClass<_typeNeeded> myClass = new MyGenericClass<typeNeeded>();

しかし、これはうまくいきません。

作成したクラスで実行時に型を設定するにはどうすればよいですか?

C#4.0を使用しています。

ありがとう。ダイムロック。

編集:私がやりたいことは次のとおりです。データベースに対していくつかのクエリを実行する必要があるクラスがあります。このクエリは常に同じ情報 (クラス) を返しますが、このクラスを含む情報は異なるテーブルから取得されます。これは、使用するクエリを決定する必要があるためです。使用するクエリを決定するには、受け取った型を使用します。

このため、設計では型がわかりませんが、実行中です。

クラスに実装されるインターフェイスを使用し、正しいクラスでインスタンス化されたインターフェイスを使用できますが、これにより、インスタンス化の瞬間にスイッチまたはifが発生し、これを回避しようとしています、もっと一般的なものが欲しいです。また、このソリューションを使用して、インスタンス化の瞬間に if を使用すると、汎用クラスを作成できるため、クラスが 1 つだけになり、保守が容易になります。

4

4 に答える 4

5

メソッドをご覧くださいMakeGenericType。これをType使用して、実行時に決定される汎用引数値を使用してインスタンスを作成できます (その後、その型のインスタンスを作成するために使用できます)。ただし、そのオブジェクトの一般的な機能を扱うときは常に、より多くのリフレクションが必要になることに注意してください。型が変数型引数を持つジェネリック型であるコードで変数を作成することはできません。

于 2012-06-10T15:04:06.057 に答える
4

別の方法でクラスを作成し、使用したい型をコンストラクターに渡してdynamicキーワードを活用することができます。

例えば:

class MyGeneralClass
{
    dynamic myVariable;
    Type type;

    public MyGeneralClass(Type type)
    {  
        this.type = type;
        myVariable = Activator.CreateInstance(type);
        //And then if your type is of a class you can use its methods      
        //e.g. myVariable.MyMethod();
    }

    //If your function return something of type you can also use dynamic
    public dynamic Function()
    {
        return Activator.CreateInstance(type);
    }
}
于 2012-06-10T17:59:19.630 に答える
3

考えてみれば、実行時に型が決定されるジェネリックを持つ理由はありません。ジェネリックは厳密な型指定を提供しますが、これはコンパイル時に型がわかっている場合にのみ可能です。これは、オブジェクトが実行できるアクションを知っているため、安全性を提供するジェネリックの最も強力な利点の 1 つです。実行時に取得する型がわからない場合は、この目的が無効になり、強力な (ただし危険な場合もある)リフレクションの世界を掘り下げる必要があります。例えば、

List<DateTime> list = new List<DateTime>();
foreach (DateTime item in list)
   item.Minute + ": " + item.Hour

コンパイル時に型がわかっているので、汎用コンテナーに格納でき、使用時に型の安全性があります。アイテムに分と時間のプロパティがあることは知っています。


オブジェクトのタイプに基づいてアクションを実行する場合は、GetType() メソッドを使用します。これは、ランタイム タイプの識別と処理へのウィンドウです。

Result PerformQuery(object unknownObject)
{
    switch (object.GetType())
    {
         case typeof(ThisType): Do This; break;
         case typeof(ThatType): Do That; break;
    }
}

オブジェクトで何かを行う場合は、コンパイル時にメソッド名を知っているため、インターフェイスを使用できるか、

IFood hamburger = new Hamburger();
hamburger.BeEaten();

インターフェイスを持っていない、または使用したくない場合は、リフレクションまたはダイナミクスを使用できます。この場合、呼び出したいメソッドがわかっている場合はダイナミックを使用します。

Result PerformQuery(object unknownObject)
{
    if (object.GetType() == typeof(Pizza))  
    {
        dynamic pizza = unknownObject;
        pizza.BakeInOven() // since I checked and know it is type Pizza it is 'somewhat' safe to do this, unless Pizza class changes the name of BakeInOven method.
     }
 }

最後に、コンパイル時に呼び出したいメソッドがわからない場合は、リフレクションを使用できます。

  string methodName = CalculateWhatMethodShouldBe();
  MethodInfo myMethod = unknownObject.GetType().GetMethods().First(m => m.Name == methodName);    
  MethodInfo.Invoke(unknownObject);
于 2012-06-10T18:27:55.677 に答える
2

あなたのコードについて十分な情報がありませんが、単純なポリモーフィズムを使用できるかもしれません:

public interface IMyInterface
{
...
}

public class MyGenericClass<T> : IMyInterface
{
....
}

IMyInterface myClass = new MyGenericClass<typeNeeded>();

これをファクトリ デザイン パターンと組み合わせて、他のクラスが実行時の知識に基づいて型のインスタンス化を担当するようにすることもできます。

もちろん、これは MyGenericClass に次のようなメソッドがないことを前提としています。

public T GetT(){...}

または、そうであれば、すべての T'types 間に追加の関係があるため、それらすべてに共通のスーパークラスがあり、BaseT と言って変更できます

public T GetT(){...}

に:

public BaseT GetT(){...}
于 2012-06-10T15:05:28.737 に答える