Bir türün bir alt tür VEYA bir nesnenin türü olup olmadığını nasıl kontrol edebilirim?


335

Bir türün C # içinde başka bir türün alt sınıfı olup olmadığını kontrol etmek için kolaydır:

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

Ancak, bu başarısız olacaktır:

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

Bir ORişleç kullanmadan veya bir uzantı yöntemi kullanmadan , bir türün temel sınıfın alt sınıfı VEYA olup olmadığını denetlemenin bir yolu var mı ?

Yanıtlar:


499

Görünüşe göre, hayır.

Seçenekler şunlardır:

Type.IsSubclassOf

Daha önce de bildiğiniz gibi, iki tür aynı ise bu çalışmaz, işte size gösteren örnek bir LINQPad programı:

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

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

Çıktı:

True
False

Bu, bunun Derivedbir alt sınıfı olduğunu Base, ancak Base(tabii ki) kendi alt sınıfı olmadığını gösterir.

Type.IsAssignableFrom

Şimdi, bu sizin özel sorunuza cevap verecektir, ancak size yanlış pozitifler de verecektir. Eric Lippert'in yorumlarda belirttiği gibi, yöntem gerçekten de Trueyukarıdaki iki soru Trueiçin geri dönerken , muhtemelen istemediğiniz bunlar için de geri dönecektir :

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 { }

Burada aşağıdaki çıktıyı elde edersiniz:

True
True
True

Sonuncusu True, eğer yöntem sadece sorulan soruya cevap verdiyse , ondan uint[]miras kaldığını int[]veya aynı tipte olduklarını gösterir, ki bu açıkça değil.

Bu IsAssignableFromda tamamen doğru değil.

is ve as

"Sorun" isve assorunuzun bağlamında onlar nesneler üzerinde işlem ve doğrudan kodda türlerinden birini değil, eser yazmak için gerektirecektir olmasıdır Typenesneler.

Başka bir deyişle, bu derlenmeyecektir:

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

bu da olmayacak:

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

bu da olmayacak:

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

Sonuç

Yukarıdaki yöntemler ihtiyaçlarınızı karşılasa da, sorunuzun (doğru olarak gördüğüm) tek doğru cevabı, ekstra bir kontrole ihtiyacınız olacaktır:

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

elbette bir yöntemde daha mantıklı:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}

2
Teşekkürler! Çekin tersine çevrilmesi gerektiğini ve MSDN belgelerine bir bağlantı sağladığından bahsettiğiniz için bunu doğru yanıt olarak işaretleyeceğim (8 dakika daha beklemeliyim).
Daniel T.

71
Bunun aslında sorunun istediğini yapmadığını unutmayın; bu, bir türün diğerinin alt sınıfı olup olmadığını değil, bir türün diğeriyle uyumlu atama olup olmadığını belirler. Bir uint dizisi, int dizisinin bir alt sınıfı değildir, ancak atama uyumludur. IEnumerable <Giraffe>, IEnumerable <Animal> alt sınıfı değildir, ancak v4'te atama uyumludur.
Eric Lippert

Bunu Java gibi yöntem adında yapmanın bir yolu yok mu? `` geçersiz <? Base> saveObject (? objectToSave) ``
Oliver Dixon

2
Buna nasıl IsInstanceOfTypeuyulur?
Lennart

IsSameOrSubclass'ı bir uzatma yöntemine dönüştürmek cazip gelebilir, ancak buna karşı öneriyorum, okumak ve yazmak biraz garip ve karıştırması kolay (potansiyelBase ve potansiyelDescendant sırasını tersine çevirmek ölümcül olabilir).
jrh



1

Bir Xamarin Forms PCL projesinde yapmaya çalışıyorsanız, yukarıdaki çözümler IsAssignableFrombir hata verir:

Hata: 'Type', 'IsAssignableFrom' için bir tanım içermiyor ve 'Type' türünün ilk bağımsız değişkenini kabul eden 'IsAssignableFrom' için bir uzantı yöntemi bulunamadı (kullanma yönergesi veya bir montaj başvurusu eksik mi?)

çünkü IsAssignableFrombir TypeInfonesne ister . GetTypeInfo()Yöntemi şuradan kullanabilirsiniz System.Reflection:

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


0

Bu yanıtı, kötü bir fikir olup olmadığı ve neden benimle paylaştığı umuduyla gönderiyorum. Uygulamamda, Typeeof (A) veya typeof (B) olduğundan emin olmak için kontrol etmek istediğim bir özellik var, burada B A'dan türetilmiş herhangi bir sınıftır. Yani benim kodum:

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;
        }
    }
}

Burada biraz naif olabileceğimi hissediyorum, bu yüzden herhangi bir geri bildirim hoş geldiniz.


2
Bu fikirle ilgili birkaç sorun vardır: 1) türün parametresiz bir kurucuya ihtiyacı varsa veya CreateInstance başarısız olur; 2) (A) 'ya döküm, döküm yapılamazsa null döndürmez; 3) yeni örneğe gerçekten ihtiyacınız yok, bu yüzden işe yaramaz bir tahsisiniz var. Kabul edilen cevap daha iyidir (mükemmel olmasa da).
Marcel Popescu

Geri dönüşünüz için teşekkür ederiz. Çok yararlı.
baskren

@baskren, belki de yararlı yorumunu iptal eder. Ben 1 numarayý oyladým.
Developer63
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.