web-dev-qa-db-ja.com

型がサブタイプORオブジェクトのタイプかどうかを確認するにはどうすればよいですか。

型がC#の別の型のサブクラスであるかどうかを確認するには、簡単です。

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // returns true

ただし、これは失敗します。

typeof (BaseClass).IsSubclassOf(typeof (BaseClass)); // returns false

OR演算子や拡張メソッドを使用せずに、型が基本クラス自体のサブクラスORであるかどうかを確認する方法はありますか?

308
Daniel T.

どうやら、いや。

これが選択肢です:

Type.IsSubclassOf

すでにご存知のとおり、2つのタイプが同じ場合は、これは機能しません。以下はその例を示す LINQPad プログラムです。

void Main()
{
    typeof(Derived).IsSubclassOf(typeof(Base)).Dump();
    typeof(Base).IsSubclassOf(typeof(Base)).Dump();
}

public class Base { }
public class Derived : Base { }

出力:

True
False

これはDerivedBaseのサブクラスであることを示しますが、Baseは(明らかに)それ自身のサブクラスではないことを示します。

Type.IsAssignableFrom

さて、これはあなたの特定の質問に答えるでしょうが、それはまたあなたに誤検知を与えるでしょう。 Eric Lippertがコメントで指摘しているように、このメソッドは実際には上記の2つの質問に対してTrueを返しますが、これらはTrueも返します。

void Main()
{
    typeof(Base).IsAssignableFrom(typeof(Derived)).Dump();
    typeof(Base).IsAssignableFrom(typeof(Base)).Dump();
    typeof(int[]).IsAssignableFrom(typeof(uint[])).Dump();
}

public class Base { }
public class Derived : Base { }

これにより、次のような出力が得られます。

True
True
True

最後のTrueは、メソッドのみが質問に答えた場合、uint[]int[]を継承していること、またはそれらが同じ型であることを示します。そうではありません。

そのためIsAssignableFromも完全に正しいわけではありません。

isおよびas

あなたの質問の文脈におけるisasの「問題」は、それらをオブジェクトに作用させてコードの中に直接タイプの1つを書くことを要求し、そしてTypeオブジェクトを扱わないことです。

言い換えれば、これはコンパイルされません。

SubClass is BaseClass
^--+---^
   |
   +-- need object reference here

またこれはしません:

typeof(SubClass) is typeof(BaseClass)
                    ^-------+-------^
                            |
                            +-- need type name here, not Type object

またこれはしません:

typeof(SubClass) is BaseClass
^------+-------^
       |
       +-- this returns a Type object, And "System.Type" does not
           inherit from BaseClass

結論

上記の方法はあなたのニーズに合うかもしれませんが、あなたの質問に対する唯一の正しい答えは(私がそれを見ているように)あなたは追加のチェックが必要になるということです:

typeof(Derived).IsSubclassOf(typeof(Base)) || typeof(Derived) == typeof(Base);

メソッドではもちろんどちらがより理にかなっている:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}
typeof(BaseClass).IsAssignableFrom(unknownType);
29
Marc Gravell

代わりに Type.IsAssignableFrom を使ってみてください。

8
Thomas

Xamarin Forms PCLプロジェクトで実行しようとしている場合、IsAssignableFromを使用した上記の解決策ではエラーが発生します。

エラー: 'Type'は 'IsAssignableFrom'の定義を含んでおらず、 'Type'型の最初の引数を受け付ける拡張メソッド 'IsAssignableFrom'が見つかりませんでした(usingディレクティブまたはアセンブリ参照がありませんか?)

なぜならIsAssignableFromTypeInfoオブジェクトを要求するからです。 System.ReflectionからGetTypeInfo()メソッドを使用できます。

typeof(BaseClass).GetTypeInfo().IsAssignableFrom(typeof(unknownType).GetTypeInfo())

1
BrunoSerrano

私はこの答えを誰かが私と共有することを願って投稿しています。私のアプリケーションでは、Typeのプロパティがあり、typeof(A)またはtypeof(B)であることを確認します。ここで、BはAから派生したクラスです。

public class A
{
}

public class B : A
{
}

public class MyClass
{
    private Type _helperType;
    public Type HelperType
    {
        get { return _helperType; }
        set 
        {
            var testInstance = (A)Activator.CreateInstance(value);
            if (testInstance==null)
                throw new InvalidCastException("HelperType must be derived from A");
            _helperType = value;
        }
    }
}

私はここで少し素朴であるかもしれないのでどんなフィードバックでも歓迎されるであろうように私は感じます。

0
baskren