Kiểm tra xem 'T' kế thừa hoặc triển khai một lớp / giao diện


92

Có cách nào để kiểm tra xem T có kế thừa / triển khai một lớp / giao diện không?

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

4
điều này dường như hoạt động ... nếu (typeof (TestClass) .IsAssignableFrom (typeof (T))), ai đó có thể xác nhận nghi ngờ của tôi không? cảm ơn!
user1229895

Tôi hoàn toàn chắc chắn rằng câu trả lời này được lặp lại nhiều lần!
Felix K.

3
Felix K Thậm chí nếu câu trả lời này đã được nhân đôi nhiều lần, nó cũng giúp rất nhiều chàng trai nhiều thời gian;) ... như tôi năm phút trước :)
Samuel

Câu trả lời:


136

Có một Phương thức được gọi là Type.IsAssignableFrom () .

Để kiểm tra xem Tkế thừa / hiện thực Employee:

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

Nếu bạn đang nhắm mục tiêu .NET Core, phương pháp đã chuyển sang TypeInfo:

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

bạn nên cập nhật câu trả lời của mình bằng một ví dụ, ví dụ: typeof (T) .IsAssignableFrom (typeof (IMyInterface))
Tiến sĩ Andrew Burnett-Thompson

Không xong nikeee; câu trả lời cũ vẫn còn đó. :) Tôi mất vài giây để tìm ra điều gì sai. Nói gì thì nói, +1, một tính năng tuyệt vời nữa của khung .net.
Samuel

Trên thực tế, cách bạn đề cập là cách tôi đã có cách đây một thời gian. Tôi đã sửa cái này. Xem các bình luận trước. T inherits Uthực sự dịch sang typeof(T).IsAssignableFrom(typeof(U)).
nikeee

2
Trong khi điều này gần như hoạt động, có một vấn đề Tlà nếu bị hạn chế đối với một số kiểu khác TOther, thì khi được thực thi, typeof(T)sẽ thực sự đánh giá typeof(TOther)và không phải bất kỳ kiểu Tnào bạn đã thực sự vượt qua và trong trường hợp đó, typeof(SomeInterface).IsAssignableFrom(typeof(T))sẽ không thành công (giả sử TOthercũng không triển khai SomeInterface), mặc dù loại bê tông của bạn đã thực hiện SomeInterface.
Dave Cousineau

1
Trong lõi .net IsAssignableFromcủa TypeInfolớp chỉ chấp nhận TypeInfo vì nó là đối số duy nhất, vì vậy mẫu phải như sau:typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo())
To Ka


16

Nếu bạn muốn kiểm tra trong quá trình biên dịch: Lỗi nếu T KHÔNG triển khai giao diện / lớp mong muốn, bạn có thể sử dụng ràng buộc sau

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

Tôi hy vọng rằng sẽ giúp.


12

Cú pháp đúng là

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

Tài liệu

Return Value: true nếu cvà hiện Typeđại diện cho cùng loại, hoặc nếu hiện tại Typelà trong hệ thống phân cấp thừa kế c, hoặc nếu hiện tại Typelà một interfacecdụng cụ, hoặc nếu clà một tham số kiểu chung chung và hiện Typeđại diện cho một trong những hạn chế của c, hoặc nếu cđại diện cho một kiểu giá trị và Typeđại diện hiện tại Nullable<c>( Nullable(Of c)trong Visual Basic). falsenếu không có điều kiện nào trong số này true, hoặc nếu cnull.

nguồn

Giải trình

Nếu Employee IsAssignableFrom Tthì Tkế thừa từ Employee.

Việc sử dụng

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

true chỉ trả lại khi một trong hai

  1. TEmployeeđại diện cho cùng một loại; hoặc là,
  2. Employeekế thừa từ T.

Đây có thể là mục đích sử dụng trong một số trường hợp, nhưng đối với câu hỏi ban đầu (và cách sử dụng phổ biến hơn), để xác định khi nào Tkế thừa hoặc triển khai một số class/ interface, hãy sử dụng:

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

9

Những gì mọi người thực sự có nghĩa là:

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

bởi vì bạn có thể chỉ định theo nghĩa đen từ một phiên bản của a DerivedTypethành một phiên bản của BaseType:

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

khi nào

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

Và một số ví dụ cụ thể nếu bạn gặp khó khăn trong việc quấn lấy nó:

(thông qua LinqPad, do đó HorizontalRunDump)

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

Các kết quả

baseclass-> baseclass

Thật

child1-> baseclass

Sai

baseclass-> child1

Thật

child2-> baseclass

Sai

baseclass-> child2

Thật

nobase-> baseclass

Sai

baseclass-> nobase

Sai

  • THẤT ​​BẠI: c1 = b1
  • b1 = c1
  • THẤT ​​BẠI: c2 = b1
  • b1 = c2

2

Tôi tin rằng cú pháp là: typeof(Employee).IsAssignableFrom(typeof(T));


Đây là cú pháp dự định. +1
Luke

0

Mặc dù IsAssignableFrom là cách tốt nhất như những người khác đã nêu, nhưng nếu bạn chỉ cần kiểm tra xem một lớp có kế thừa từ lớp khác hay typeof(T).BaseType == typeof(SomeClass)không , thì công việc cũng vậy.


Điều đó hoạt động trừ khi SomeClasskhông có nguồn gốc trực tiếp từ BaseClass.
Suncat2000

0

Các cách thay thế để biết một đối tượng okế thừa một lớp hoặc triển khai một giao diện là sử dụng toán tử isand as.

Nếu bạn chỉ muốn biết liệu một đối tượng có kế thừa một lớp hay triển khai một giao diện hay không, istoán tử sẽ trả về một kết quả boolean:

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

Nếu bạn muốn sử dụng lớp kế thừa hoặc giao diện được triển khai sau khi kiểm tra của mình, asnhà điều hành sẽ thực hiện truyền an toàn, trả về một tham chiếu đến lớp kế thừa hoặc giao diện được triển khai nếu tương thích hoặc null nếu không tương thích:

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.

Nếu bạn chỉ có loại T, thì hãy sử dụng câu trả lời của @ nikeee.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.