4

ジェネリック型を比較す​​るis演算子に問題があります。

 public interface ISomeInterface<T> where T : SomeBaseClass{
 }

 public class SomeClass : SomeBaseClass{
 }

ここで、is演算子を使用して型を確認します。インターフェイスISomeInterfaceを実装するクラスのインスタンスがあります。

残念ながら、次の問題に直面しています。

 // someObject is an Instance of a class implementing interface ISomeInterface<SomeClass>
 bool isSomeBaseClass = someObject is ISomeInterface<SomeBaseClass>; // false
 bool isSomeClass = someObject is ISomeInterface<SomeClass>; // true

変数のジェネリック型をチェックすることは可能ですか?

よろしくお願いします、トビ

4

4 に答える 4

10

これはジェネリック共分散と呼ばれ、C#4.0でサポートされています。次のキーワードでジェネリックTパラメータをマークできます。out

public interface ISomeInterface<out T> where T : SomeBaseClass

ただし、これには制限があります。パラメータは、インターフェイスのメソッドのT戻り型としてのみ表示できます。

Eric Lippertには、このテーマに関する一連のブログ投稿がありますので、ぜひお読みください。

于 2012-06-25T09:21:15.400 に答える
5

inはい、 andoutキーワードを使用して共変性と反変性を利用できます。

public interface ISomeInterface<in T> where T : SomeBaseClass{

}

または:

public interface ISomeInterface<out T> where T : SomeBaseClass{

}

ただし、キーワードinを使用するとTをパラメーターとして使用でき、それ以外の場合はTを戻り型としてout使用できることに注意してください。

共分散:

X<S>からに変換できる場合、タイプは共変ですX<B>

共変性:

X<B>からに変換できる場合、タイプは反変ですX<S>

-ここで、Sはサブクラス、Bはベースクラスです。


C#4.0の本を読んでいたときに学んだ興味深い例は、Stackに関するものでした。

class Stack<T>{
   int i;
   T[] array = new T[1000];
   public void Push(T element){
       array[i++] = element;
   }
}

class BaseClass{
}

class SubClass : BaseClass{
}

実際、Stackがこのインターフェースを実装する場合、この場合、反変性が使用される可能性があることを説明しています。

interface IPushable<in T>{
    void Push(T element);
}

それで:

IPushable<BaseClass> stackB = new Stack<BaseClass>();
IPushable<SubClass> stackS = stackB;
stackS.Push(new SubClass());

この場合、共分散は次のインターフェースを実装します。

interface IPoppable<in T>{
    T Pop();
}

それで:

IPoppable<SubClass> stackS = new Stack<SubClass>();
IPoppable<BaseClass> stackB = stackB;
BaseClass baseClass = stackB.Pop();

これは、問題やコンパイル時エラーなしでアップキャストとダウンキャストを許可するため、非常に役立ちます。

于 2012-06-25T09:23:10.697 に答える
1

あなたの質問を正しく理解したかどうかはわかりませんが、クラスがジェネリッククラスから派生しているかどうかを確認するで答えるようなものが必要になる場合があります。

public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
{
   while (toCheck != null && toCheck != typeof(object))
   {
      var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
      if (generic == cur)
            return true;
      toCheck = toCheck.BaseType;
   }
   return false;
}
于 2012-06-25T09:23:11.050 に答える
0

答えは、あなたが達成しようとしていることを示しているように見えるので、2番目の質問から始まります。

IList<string>Q:しかし、のオブジェクトについてtrueを取得したい場合、どうすれば確認できますIList<object>か?

文字列はオブジェクトから継承するため、一般的なケースでは条件付きパターンでそれをチェックする必要があると考えられます。

IList<string> stringList = new List<string>();  
IList<object> objectList = new List<object>();


stringList is IList<string>;
//> true
stringList is IList<object>;
//> false
objectList is IList<string>;
//> false
objectList is IList<object>;
//>true
"someString" is object
//> true

したがって、Generic-Typeコンストラクトのタイプを確認するだけです。

IsGenericTypeそれぞれまたはの先行するブールチェックとともにIsGenericConstructedType

objectList.GetType().GenericTypeArguments[0] is object
//> true
stringList.GetType().GenericTypeArguments[0] is object
//> true

警告:nullの場合を確認してください。言語的にサポートされている場合は、null合体および/またはnull条件演算子を使用するなど...簡潔さと明確さのために例には含まれていません


Q:変数(継承された)ジェネリック型をチェックすることは可能ですか?

ダリンとfuexによる回答に加えて、さらなるポインタ:

  • のIEquality実装を使用して、Type厳密な型チェックを行うことができます。

    bool condition = (someObject != null 
                      && someObject.GetType().Equals(typeof(ISomeInterface<SomeClass>)) );
    
  • インターフェイスを明示的にチェックします。

    var interfaces = someType.GetType().GetInterfaces(); 
    //DotNet4.5: var interfaces = someType.GetType()
    //               .GetTypeInfo().ImplementedInterfaces;
    bool condition = (interfaces != null && interfaces.ToList()
                     .Contains(typeof(ISomeInterface<SomeClass>)) == true);
    

TypeとTypeInfoを使用して、ほぼすべての条件付きチェックを作成できます。

于 2016-07-28T07:06:34.207 に答える