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


335

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

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

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

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

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

回答:


498

どうやら、違います。

オプションは次のとおりです。

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

これは、それDerivedがのサブクラスであることを示していますBaseが、それBaseは(明らかに)それ自体のサブクラスではありません。

Type.IsAssignableFrom

これで、特定の質問に答えることができますが、誤検知も発生します。Eric Lippertがコメントで指摘したように、メソッドは確かにTrue上記の2つの質問に対して返さ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;
}

2
ありがとう!チェックを元に戻す必要があると述べ、MSDNドキュメントへのリンクを提供したので、これを正しい答えとしてマークします(さらに8分待つ必要があります)。
ダニエルT.

71
これは実際には質問が要求したことを実行しないことに注意してください。これは、あるタイプが別のタイプのサブクラスであるかどうかではなく、あるタイプが別のタイプと割り当て互換であるかどうかを決定します。uintの配列はintの配列のサブクラスではありませんが、割り当てには互換性があります。IEnumerable <Giraffe>はIEnumerable <Animal>のサブクラスではありませんが、v4では割り当て互換です。
Eric Lippert、2010

Javaのようなメソッド名でこれを行う方法はありませんか?`` `void <?拡張Base> saveObject(?objectToSave) `` `
Oliver Dixon

2
これにどのようにIsInstanceOfType適合しますか?
Lennart

IsSameOrSubclassを拡張メソッドに変換するのは魅力的かもしれませんが、これはお勧めしません。読み取りと書き込みが少し厄介で、混乱する可能性があります(potentialBaseとpotentialDescendantの順序を逆にすることは致命的です)。
jrh 2017



1

Xamarin Forms PCLプロジェクトでそれを実行しようとしている場合、上記のソリューションを使用IsAssignableFromするとエラーが発生します。

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

オブジェクトをIsAssignableFrom要求するからTypeInfoです。次のGetTypeInfo()方法を使用できますSystem.Reflection

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


0

私はこの答えを投稿します。誰かが私にそれを共有することを期待しています。私のアプリケーションには、typeof(A)またはtypeof(B)であることを確認するために確認したいTypeのプロパティがあります。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;
        }
    }
}

私はここでは少し世間知らずかもしれないので、どんなフィードバックでも歓迎します。


2
このアイデアにはいくつかの問題があります。1)型にパラメーターなしのコンストラクターが必要であるか、CreateInstanceが失敗する。2)(A)へのキャストは、キャストができない場合はnullを返しません。スローします。3)実際には新しいインスタンスは必要ないので、無駄な割り当てがあります。受け入れられた回答の方が優れています(完璧ではありません)。
Marcel Popescu

フィードバックをお寄せいただきありがとうございます。非常に役立ちます。
baskren 2017

@baskren、おそらく彼の有用なコメントに賛成票を投じる。#1に賛成票を投じました。
Developer63
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.