47

私はジェネリック型を持っており、この型のインスタンスを作成するためにStore<T>使用しています。ActivatorActivator を使用した後、結果の型のオブジェクトをobjectインスタンス化された型に戻すにはどうすればよいでしょうか? ジェネリックをインスタンス化するために使用した型を知っています。次のコードを参照してください。

class Store<T> where T : IStorable 
{}

class Beer : IStorable 
{}

class BeerStore : Store<Beer>
{}

Type storeType = someObjectThatImplementsIStorable.GetType();
Type classType = typeof(Store<>);
Type[] typeParams = new Type[] { storeType };   
Type constructedType = classType.MakeGenericType(typeParams);

object x = Activator.CreateInstance(constructedType, new object[] { someParameter });

私がやりたいことは次のようなものです:

var store = (Store<typeof(objectThatImplementsIStorable)>)x;

しかし、それは明らかな理由で機能しません。別の方法として、私が試した:

var store = (Store<IStorable>)x;

私の意見ではおそらくうまくいくかもしれませんが、InvalidCastException.

Store<T>object 内にあることがわかっているメソッドに再度アクセスするにはどうすればよいxですか?

4

5 に答える 5

35

実際の型Tはリフレクションを介してのみ利用できるため、リフレクションのメソッドにもアクセスする必要がありますStore<T>

Type constructedType = classType.MakeGenericType(typeParams);

object x = Activator.CreateInstance(constructedType, new object[] { someParameter });
var method = constructedType.GetMethod("MyMethodTakingT");
var res = method.Invoke(x, new object[] {someObjectThatImplementsStorable});

編集IStoreジェネリックを使用せず、IStorable代わりに使用する追加のインターフェースを定義することもできます。

interface IStore {
    int CountItems(IStorable item);
}
class Store<T> : IStore where T : IStorable {
    int CountItems(IStorable item) {
        return count;
    }
}

あなたStore<T>はジェネリックのままですが、CountItemsにキャストすることでアクセスできますIStore

var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter });
var count = x.CountItems((IStorable)someObjectThatImplementsStorable);
于 2012-02-04T12:44:45.997 に答える
7

巻いていただけませんか?

何かのようなもの

public Store<T> IConstructStore<T>(T item) where T : IStorable 
{
 return Activator.CreateInstance(typeof(Store<T>), new object[] { someParameter }) as Store<T>;
}

または、あなたがやろうとしていることを見逃していますか?

IE

class Program
{
    static void Main(string[] args)
    {
        Beer b = new Beer();
        var beerStore = IConstructStore(b);
        Console.WriteLine(beerStore.test);
        Console.WriteLine(beerStore.GetType().ToString());
    }

    public static Store<T> IConstructStore<T>(T item) where T : IStorable
    {
        return Activator.CreateInstance(typeof(Store<T>), new object[] { }) as Store<T>;
    }
}

interface IStorable { }

class Store<T> where T : IStorable
{
    public int test = 1;
}

class Beer : IStorable
{ }

版画

1 
ConsoleApp1.Store'1[ConsoleApp1.Beer]
于 2012-02-04T12:42:19.977 に答える
3

私の意見では、最も適切な答えは「この方法ではできない」です。

インターフェイスを導入しIStorageて、それを共変または反変にしようとするかもしれません (そのオプションを見たことがありますか?)。それがオプションでない場合、たとえば、入力と出力の両方のジェネリック型が で使用されStorageている場合、必要なものを実装する方法はありません。その理由は、次の場合のStorage<Beer>ように安全に使用できないためですStorage<IStorable>

Storage<IStorable> store = new Storage<Beer>(); // let's pretend we can do it 
store.Save(new StorableButNotBeer()); // what will happen here?

私が見た唯一の回避策は、このメソッドからキャストを移動し、すべての正確な型がわかっている場所にオブジェクトをキャストすることです。

public void object CreateStore(Type istorableType)
{
    // here is your activator code, but you will have to return an object
}

var beerStore = (Store<Beer>)CreateStore(typeof(Beer));
于 2012-02-04T12:49:58.150 に答える
0

someObjectThatImplementsIStorable が MyStorable 型であるとしましょう。

例: MyStorable someObjectThatImplementsIStorable = new MyStorable( ); ... // ここに残りのコード。

x を Store にキャストすることはできませんが、Store にキャストすることはできます。以下が機能します: (Store)x

MyStorable は IStorable を実装していますが、Store と Store の間には関係がないことに注意してください。これらは、互いに派生しない 2 つの異なるクラスです。

あなた。

于 2012-02-04T12:53:55.763 に答える