2008-10-08 31 views
118

Đoạn mã nào nhanh hơn?là so với typeof

if (obj is ClassA) {} 

if (obj.GetType() == typeof(ClassA)) {} 

Chỉnh sửa: Tôi biết rằng chúng không thực hiện tương tự.

+1

Đã trả lời một câu hỏi tương tự tại đây: http://stackoverflow.com/questions/57701/what-are-the-performance-characteristics -of-is-reflection-in-C# 57713 – swilliams

Trả lời

142

This should answer that question, and then some.

Dòng thứ hai, if (obj.GetType() == typeof(ClassA)) {}, là nhanh hơn, cho những người không muốn đọc bài viết.

+1

+1: Trong quá khứ tôi tự hỏi tại sao trình biên dịch C# không biên dịch 'typeof (string) .TypeHandle' thành lệnh' ldtoken' CIL, nhưng nó trông giống như CLR chăm sóc nó trong JIT. Nó vẫn cần thêm một vài opcodes nhưng nó là một ứng dụng tổng quát hơn về tối ưu hóa. –

+2

Đọc http://higherlogics.blogspot.ca/2013/09/clr-cost-of-dynamic-type-tests.html quá - họ thử lại cho các khuôn khổ khác nhau và x86 vs x64 với kết quả khác nhau rộng rãi. –

+1

Xin lưu ý rằng điều này chỉ đúng đối với các loại tham chiếu. Và sự khác biệt về tốc độ không phải là đáng kể. Với hình phạt quyền anh trong trường hợp các kiểu giá trị cho 'GetType',' is' luôn là lựa chọn an toàn hơn nhiều so với hiệu năng. Tất nhiên họ làm những việc khác nhau. – nawfal

23

Chúng không làm tương tự. Việc đầu tiên hoạt động nếu obj là loại ClassA hoặc của một số phân lớp của ClassA. Cái thứ hai sẽ chỉ khớp với các đối tượng thuộc loại ClassA. Cái thứ hai sẽ nhanh hơn vì nó không phải kiểm tra phân cấp lớp.

Đối với những người muốn biết lý do, nhưng không muốn đọc bài viết được tham chiếu trong is vs typeof.

+0

http://stackoverflow.com/q/27813304 cho biết 'Object is Type' sẽ nhanh hơn. –

+1

@amitjha Tôi hơi lo ngại vì thử nghiệm đó được chạy dưới Mono rằng nó không bao gồm các tối ưu hóa JIT được tham chiếu trong bài viết. Vì bài báo cho thấy điều ngược lại, trong tâm trí tôi câu hỏi là một câu hỏi mở. Trong mọi trường hợp, so sánh hiệu suất hoạt động làm những việc khác nhau tùy thuộc vào loại có vẻ là một bài tập vô giá trị. Sử dụng các hoạt động phù hợp với hành vi bạn cần, không phải là một trong đó là "nhanh hơn" – tvanfosson

153

Có vấn đề gì nhanh hơn, nếu họ không làm điều tương tự? So sánh hiệu suất của các câu với ý nghĩa khác nhau có vẻ như là một ý tưởng tồi.

is cho bạn biết liệu đối tượng có thực hiện ClassA ở bất kỳ đâu trong chế độ thừa kế kiểu của nó hay không. GetType() cho bạn biết về loại có nguồn gốc cao nhất.

Không giống nhau.

+6

Nó không quan trọng, bởi vì trong trường hợp của tôi tôi tích cực họ trở lại cùng một kết quả. – ilitirit

+28

@ [ilitirit]: chúng cũng trả về cùng một kết quả ngay bây giờ, nhưng nếu bạn thêm một phân lớp sau thì chúng sẽ không –

+10

Tối ưu hóa bây giờ sẽ làm cho mã của bạn trở nên giòn và khó bảo trì. – ICR

9

Tôi đã thực hiện một số điểm chuẩn nơi chúng thực hiện cùng các loại được niêm phong.

var c1 = ""; 
var c2 = typeof(string); 
object oc1 = c1; 
object oc2 = c2; 

var s1 = 0; 
var s2 = '.'; 
object os1 = s1; 
object os2 = s2; 

bool b = false; 

Stopwatch sw = Stopwatch.StartNew(); 
for (int i = 0; i < 10000000; i++) 
{ 
    b = c1.GetType() == typeof(string); // ~60ms 
    b = c1 is string; // ~60ms 

    b = c2.GetType() == typeof(string); // ~60ms 
    b = c2 is string; // ~50ms 

    b = oc1.GetType() == typeof(string); // ~60ms 
    b = oc1 is string; // ~68ms 

    b = oc2.GetType() == typeof(string); // ~60ms 
    b = oc2 is string; // ~64ms 


    b = s1.GetType() == typeof(int); // ~130ms 
    b = s1 is int; // ~50ms 

    b = s2.GetType() == typeof(int); // ~140ms 
    b = s2 is int; // ~50ms 

    b = os1.GetType() == typeof(int); // ~60ms 
    b = os1 is int; // ~74ms 

    b = os2.GetType() == typeof(int); // ~60ms 
    b = os2 is int; // ~68ms 


    b = GetType1<string, string>(c1); // ~178ms 
    b = GetType2<string, string>(c1); // ~94ms 
    b = Is<string, string>(c1); // ~70ms 

    b = GetType1<string, Type>(c2); // ~178ms 
    b = GetType2<string, Type>(c2); // ~96ms 
    b = Is<string, Type>(c2); // ~65ms 

    b = GetType1<string, object>(oc1); // ~190ms 
    b = Is<string, object>(oc1); // ~69ms 

    b = GetType1<string, object>(oc2); // ~180ms 
    b = Is<string, object>(oc2); // ~64ms 


    b = GetType1<int, int>(s1); // ~230ms 
    b = GetType2<int, int>(s1); // ~75ms 
    b = Is<int, int>(s1); // ~136ms 

    b = GetType1<int, char>(s2); // ~238ms 
    b = GetType2<int, char>(s2); // ~69ms 
    b = Is<int, char>(s2); // ~142ms 

    b = GetType1<int, object>(os1); // ~178ms 
    b = Is<int, object>(os1); // ~69ms 

    b = GetType1<int, object>(os2); // ~178ms 
    b = Is<int, object>(os2); // ~69ms 
} 

sw.Stop(); 
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString()); 

Các chức năng tổng quát để kiểm tra đối với các loại generic:

static bool GetType1<S, T>(T t) 
{ 
    return t.GetType() == typeof(S); 
} 
static bool GetType2<S, T>(T t) 
{ 
    return typeof(T) == typeof(S); 
} 
static bool Is<S, T>(T t) 
{ 
    return t is S; 
} 

tôi đã cố gắng với nhiều loại tùy chỉnh như tốt và kết quả vẫn y nguyên:

var c1 = new Class1(); 
var c2 = new Class2(); 
object oc1 = c1; 
object oc2 = c2; 

var s1 = new Struct1(); 
var s2 = new Struct2(); 
object os1 = s1; 
object os2 = s2; 

bool b = false; 

Stopwatch sw = Stopwatch.StartNew(); 
for (int i = 0; i < 10000000; i++) 
{ 
    b = c1.GetType() == typeof(Class1); // ~60ms 
    b = c1 is Class1; // ~60ms 

    b = c2.GetType() == typeof(Class1); // ~60ms 
    b = c2 is Class1; // ~55ms 

    b = oc1.GetType() == typeof(Class1); // ~60ms 
    b = oc1 is Class1; // ~68ms 

    b = oc2.GetType() == typeof(Class1); // ~60ms 
    b = oc2 is Class1; // ~68ms 


    b = s1.GetType() == typeof(Struct1); // ~150ms 
    b = s1 is Struct1; // ~50ms 

    b = s2.GetType() == typeof(Struct1); // ~150ms 
    b = s2 is Struct1; // ~50ms 

    b = os1.GetType() == typeof(Struct1); // ~60ms 
    b = os1 is Struct1; // ~64ms 

    b = os2.GetType() == typeof(Struct1); // ~60ms 
    b = os2 is Struct1; // ~64ms 


    b = GetType1<Class1, Class1>(c1); // ~178ms 
    b = GetType2<Class1, Class1>(c1); // ~98ms 
    b = Is<Class1, Class1>(c1); // ~78ms 

    b = GetType1<Class1, Class2>(c2); // ~178ms 
    b = GetType2<Class1, Class2>(c2); // ~96ms 
    b = Is<Class1, Class2>(c2); // ~69ms 

    b = GetType1<Class1, object>(oc1); // ~178ms 
    b = Is<Class1, object>(oc1); // ~69ms 

    b = GetType1<Class1, object>(oc2); // ~178ms 
    b = Is<Class1, object>(oc2); // ~69ms 


    b = GetType1<Struct1, Struct1>(s1); // ~272ms 
    b = GetType2<Struct1, Struct1>(s1); // ~140ms 
    b = Is<Struct1, Struct1>(s1); // ~163ms 

    b = GetType1<Struct1, Struct2>(s2); // ~272ms 
    b = GetType2<Struct1, Struct2>(s2); // ~140ms 
    b = Is<Struct1, Struct2>(s2); // ~163ms 

    b = GetType1<Struct1, object>(os1); // ~178ms 
    b = Is<Struct1, object>(os1); // ~64ms 

    b = GetType1<Struct1, object>(os2); // ~178ms 
    b = Is<Struct1, object>(os2); // ~64ms 
} 

sw.Stop(); 
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString()); 

Và các loại:

sealed class Class1 { } 
sealed class Class2 { } 
struct Struct1 { } 
struct Struct2 { } 

Suy luận:

  1. Calling GetType trên struct s là chậm hơn.GetType được định nghĩa trên object lớp không thể ghi đè trong các loại phụ và do đó struct cần phải được đóng hộp để được gọi là GetType.

  2. Trên trường hợp đối tượng, GetType là nhanh hơn, nhưng rất nhỏ.

  3. On kiểu generic, nếu Tclass, sau đó is là nhanh hơn nhiều. Nếu Tstruct thì is nhanh hơn nhiều so với GetType nhưng typeof(T) nhanh hơn cả hai. Trong trường hợp Tclass, typeof(T) không đáng tin cậy vì nó khác với loại cơ bản thực tế t.GetType.

Tóm lại, nếu bạn có một ví dụ object, hãy sử dụng GetType. Nếu bạn có loại class chung, hãy sử dụng is. Nếu bạn có loại struct chung, hãy sử dụng typeof(T). Nếu bạn không chắc chắn nếu loại chung là loại tham chiếu hoặc loại giá trị, hãy sử dụng is. Nếu bạn muốn nhất quán với một kiểu luôn (đối với loại kín), hãy sử dụng is ..

+0

Trong thực tế, không quan tâm gì cả. Sử dụng những gì có ý nghĩa nhất. – nawfal

Các vấn đề liên quan