3

ジェネリック クラス内の静的フィールドからジェネリック型のインスタンス値を取得しようとしていますが、次の例外がスローされます。

Type.ContainsGenericParameters が true である型のフィールドに対してレイト バインド操作を実行することはできません

public class ManagerTemplate<Q, T> : IObjectManager
        where T : Filmation.Runtime.Engine.ObjectId, new( )
        where Q : ManagerTemplate<Q, T>, new( ) {

        public readonly static Q Instance = new Q( );         <---- STATIC FIELD
}


private static void FindManagers( ) {
    var IObjectManagerType = typeof( IObjectManager );

    var managers = IObjectManagerType.Assembly
          .GetTypes( )
          .Where( t => !t.IsAbstract && t.GetInterfaces().Any( i => i == IObjectManagerType) );

    foreach (var manager in managers) {
         var fi = manager.GetField( "Instance" );
         var instance = fi.GetValue( null );                  <--- EXCEPTION
    }
}

GetGenericTypeDefinition を使用しようとしましたが、引き続き例外がスローされます。

Googleで検索しましたが、それを行う方法が見つかりませんでした...

誰でもそれができる方法を知っていますか?

編集:静的プロパティを使用して同じ

これは私が実装した回避策です(ただし、リフレクションを使用して実行できるかどうかを知りたいです):

public static Q Instance { get; private set; }

static ManagerTemplate( ) {
     Instance = new Q( );
     Environment.Managers.Add( Instance );
}
4

3 に答える 3

3

の具体的な型がないという理由だけで、ジェネリック型定義public readonly static Q Instance = new Q( );からの値を取得することはできません。 ManagerTemplate<Q, T>Q

具象型が何であるかをまだQ知らない場合、ジェネリック型定義のインスタンスを取得するにはどうすればよいでしょうか? シンプル: できません。Q

今...取得したいのManagerTemplate<Q, T>が、ジェネリック型パラメーターQが定義されている場所から派生した型のインスタンスである場合、実際にはジェネリック型パラメーターを検索から除外する必要があります。

private static IEnumerable<IObjectManager> FindManagers()
{
  Type type = typeof(IObjectManager);
  IEnumerable<Type> managers = type.Assembly
                   .GetTypes()
                   .Where(t => !t.IsAbstract && t.GetInterfaces().Contains(type));

  foreach (Type manager in managers)
  {
    var fi = manager.GetField("Instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
    if (fi != null && 
       !fi.FieldType.IsGenericParameter && 
        type.IsAssignableFrom(fi.FieldType))
    {
      yield return (IObjectManager) fi.GetValue(null);
    }
  }
}

ManagerTemplate<Q, T>これにより、タイプが何であるかを定義したすべてのクラスで定義されたすべての「マネージャー」が取得されますQ

于 2013-08-10T01:25:07.253 に答える
3

問題は、バインドされていないジェネリック型、つまり型引数が指定されていないジェネリック型から Instance フィールドを取得しようとしていることです。バインドされていない型をインスタンス化することも、そのメソッドを呼び出すこともできません。すべての型パラメーターが指定されたバインドされたジェネリック型が必要ですが、それぞれの異なる具体的なバインドされた型が静的フィールドを共有しないことを考慮してください。たとえばManagerTemplate<Class1, Class2>、別のインスタンスを返しManagerTemplate<Class1, Class3>ます。ただし、のすべてのインスタンスはManagerTemplate<Class1, Class2>static フィールドを共有します。

リフレクションを使用して、バインドされていないジェネリック型の未指定の型パラメーターに型引数をバインドできますType.MakeGenericType。FindManagers クラスに型引数を提供する必要があります。

private static void FindManagers<Q,T>( ) {
    var IObjectManagerType = typeof( IObjectManager );

    var managers = IObjectManagerType.Assembly
          .GetTypes( )
          .Where( t => !t.IsAbstract && t.GetInterfaces().Any( i => i == IObjectManagerType) );

    foreach (var manager in managers) {
         var concreteType = manager.MakeGenericType(typeof(Q), typeof(T));
         var fi = concreteType.GetField( "Instance" );
         var instance = fi.GetValue( null );                
    }
}
于 2013-08-10T01:12:02.987 に答える