ตรวจสอบว่า 'T' สืบทอดหรือใช้คลาส / อินเทอร์เฟซหรือไม่


94

มีวิธีทดสอบว่า T สืบทอด / ใช้คลาส / อินเทอร์เฟซหรือไม่?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}

4
ดูเหมือนจะใช้งานได้ ... ถ้า (typeof (TestClass) .IsAssignableFrom (typeof (T))) มีใครยืนยันข้อสงสัยของฉันได้ไหม ขอบคุณ!
user1229895

ฉันแน่ใจจริงๆว่าคำตอบนี้ซ้ำกันหลายครั้ง!
Felix K.

3
Felix K แม้ว่าคำตอบนี้จะซ้ำกันหลายครั้ง แต่ก็ยังช่วยคนได้หลายครั้ง;) ... เหมือนฉันเมื่อห้านาทีก่อน :)
ซามูเอล

คำตอบ:


139

มีวิธีการที่เรียกว่าเป็นType.IsAssignableFrom ()

วิธีตรวจสอบว่าTสืบทอด / ดำเนินการหรือไม่Employee:

typeof(Employee).IsAssignableFrom(typeof(T));

หากคุณกำหนดเป้าหมาย. NET Core วิธีนี้ได้ย้ายไปที่ TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())

คุณควรอัปเดตคำตอบของคุณด้วยตัวอย่างเช่น typeof (T) IsAssignableFrom (typeof (IMyInterface))
Dr. Andrew Burnett-Thompson

ไม่ได้ทำ nikeee; คำตอบเก่ายังคงมีอยู่ :) ฉันใช้เวลาสองสามวินาทีเพื่อหาว่ามีอะไรผิดปกติ อย่างไรก็ตาม +1 คุณลักษณะที่ดีอีกครั้งของ. net framework
ซามูเอล

อันที่จริงวิธีที่คุณพูดถึงเป็นวิธีที่ฉันเคยมีมาก่อน ฉันแก้ไขอันนี้ ดูความคิดเห็นก่อนหน้านี้ T inherits Uแปลเป็นtypeof(T).IsAssignableFrom(typeof(U)).
nikeee

3
แม้ว่าสิ่งนี้จะใช้งานได้เกือบจะมีปัญหาที่หากTถูก จำกัด ให้เป็นประเภทอื่นTOtherเมื่อดำเนินการแล้วtypeof(T)จะประเมินเป็นจริงtypeof(TOther)ไม่ใช่ประเภทใดก็ตามที่Tคุณผ่านมาจริงและในกรณีนั้นtypeof(SomeInterface).IsAssignableFrom(typeof(T))จะล้มเหลว (โดยถือว่าTOtherไม่ได้ใช้งานด้วยSomeInterface) แม้ว่าประเภทคอนกรีตของคุณจะใช้งานSomeInterfaceได้
Dave Cousineau

1
ใน. net core IsAssignableFromของTypeInfoclass ยอมรับเฉพาะ TypeInfo เนื่องจากเป็นอาร์กิวเมนต์เท่านั้นดังนั้นตัวอย่างควรเป็นดังนี้:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
ถึง Ka


16

หากคุณต้องการตรวจสอบระหว่างการคอมไพล์: เกิดข้อผิดพลาดหากT ไม่ใช้อินเตอร์เฟส / คลาสที่ต้องการคุณสามารถใช้ข้อ จำกัด ต่อไปนี้

public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
    //Code of my method here, clean without any check for type constraints.
}

ฉันหวังว่าจะช่วยได้


13

ไวยากรณ์ที่ถูกต้องคือ

typeof(Employee).IsAssignableFrom(typeof(T))

เอกสารประกอบ

ค่าส่งกลับ: trueถ้าcและปัจจุบันTypeเป็นตัวแทนประเภทเดียวกันหรือถ้ากระแสTypeอยู่ในลำดับชั้นการสืบทอดของcหรือถ้ากระแสTypeเป็นสิ่งinterfaceที่cดำเนินการหรือถ้าcเป็นพารามิเตอร์ประเภททั่วไปและปัจจุบันTypeแสดงถึงข้อ จำกัด อย่างใดอย่างหนึ่งของcหรือ ถ้าcแสดงถึงชนิดค่าและปัจจุบันTypeแสดงNullable<c>( Nullable(Of c)ใน Visual Basic) falseถ้าไม่มีเงื่อนไขเหล่านี้trueหรือถ้ามีcnull

แหล่งที่มา

คำอธิบาย

หากEmployee IsAssignableFrom Tแล้วสืบทอดจากTEmployee

การใช้งาน

typeof(T).IsAssignableFrom(typeof(Employee)) 

ส่งคืนtrue ก็ต่อเมื่ออย่างใดอย่างหนึ่ง

  1. TและEmployeeเป็นตัวแทนประเภทเดียวกัน หรือ,
  2. EmployeeสืบทอดมาจากT.

นี่อาจเป็นการใช้งานตามวัตถุประสงค์ในบางกรณี แต่สำหรับคำถามเดิม (และการใช้งานทั่วไป) เพื่อพิจารณาว่าเมื่อใดที่Tสืบทอดหรือดำเนินการclass/ interfaceใช้:

typeof(Employee).IsAssignableFrom(typeof(T))

9

สิ่งที่ทุกคนหมายถึงคือ:

typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true

เพราะคุณสามารถกำหนดจากอินสแตนซ์ของ a DerivedTypeไปยังอินสแตนซ์ของBaseType:

DerivedType childInstance = new DerivedType();
BaseType parentInstance = childInstance; // okay, assigning base from derived
childInstance = (DerivedType) parentInstance; // not okay, assigning derived from base

เมื่อไหร่

public class BaseType {}
public class DerivedType : BaseType {}

และตัวอย่างที่เป็นรูปธรรมหากคุณมีปัญหาในการพันศีรษะ:

(ผ่าน LinqPad ด้วยเหตุนี้HorizontalRunและDump)

void Main()
{
    // http://stackoverflow.com/questions/10718364/check-if-t-inherits-or-implements-a-class-interface

    var b1 = new BaseClass1();

    var c1 = new ChildClass1();
    var c2 = new ChildClass2();
    var nb = new nobase();

    Util.HorizontalRun(
        "baseclass->baseclass,child1->baseclass,baseclass->child1,child2->baseclass,baseclass->child2,nobase->baseclass,baseclass->nobase",
        b1.IsAssignableFrom(typeof(BaseClass1)),
        c1.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass1)),
        c2.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass2)),
        nb.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(nobase))
        ).Dump("Results");

    var results = new List<string>();
    string test;

    test = "c1 = b1";
    try {
        c1 = (ChildClass1) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c1";
    try {
        b1 = c1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "c2 = b1";
    try {
        c2 = (ChildClass2) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c2";
    try {
        b1 = c2;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    results.Dump();
}

// Define other methods and classes here
public static class exts {
    public static bool IsAssignableFrom<T>(this T entity, Type baseType) {
        return typeof(T).IsAssignableFrom(baseType);
    }
}


class BaseClass1 {
    public int id;
}

class ChildClass1 : BaseClass1 {
    public string name;
}

class ChildClass2 : ChildClass1 {
    public string descr;
}

class nobase {
    public int id;
    public string name;
    public string descr;
}

ผล

ชั้นฐาน -> ชั้นฐาน

จริง

child1-> baseclass

เท็จ

baseclass-> child1

จริง

child2-> baseclass

เท็จ

baseclass-> child2

จริง

nobase-> เบสคลาส

เท็จ

baseclass-> nobase

เท็จ

และ

  • ความล้มเหลว: c1 = b1
  • b1 = c1
  • ล้มเหลว: c2 = b1
  • b1 = c2

2

ฉันเชื่อว่าไวยากรณ์คือ: typeof(Employee).IsAssignableFrom(typeof(T));


นี่คือไวยากรณ์ที่ต้องการ +1
ลุค

0

แม้ว่า IsAssignableFrom จะเป็นวิธีที่ดีที่สุดตามที่ผู้อื่นระบุไว้ แต่หากคุณต้องการตรวจสอบว่าคลาสที่สืบทอดมาจากคลาสอื่นtypeof(T).BaseType == typeof(SomeClass)ก็จะทำงานได้เช่นกัน


เว้นแต่ว่างานจะไม่ได้รับโดยตรงจากSomeClass BaseClass
Suncat2000

0

วิธีอื่นในการบอกว่าอ็อบเจ็กต์oสืบทอดคลาสหรือใช้อินเทอร์เฟซคือการใช้ตัวดำเนินการisและas

หากคุณต้องการทราบเฉพาะว่าอ็อบเจ็กต์สืบทอดคลาสหรือใช้อินเทอร์เฟซตัวisดำเนินการจะส่งคืนผลลัพธ์บูลีน:

bool isCompatibleType = (o is BaseType || o is IInterface);

หากคุณต้องการใช้คลาสที่สืบทอดมาหรืออินเทอร์เฟซที่นำมาใช้หลังจากการทดสอบของคุณasโอเปอเรเตอร์จะทำการแคสต์ที่ปลอดภัยโดยส่งคืนการอ้างอิงไปยังคลาสที่สืบทอดมาหรืออินเทอร์เฟซที่ใช้งานหากเข้ากันได้หรือเป็นโมฆะหากไม่เข้ากัน

BaseType b = o as BaseType; // Null if d does not inherit from BaseType.

IInterface i = o as IInterface; // Null if d does not implement IInterface.

หากคุณมีเพียงประเภทTให้ใช้คำตอบของ @ nikeee

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.