là vs


150

Những đoạn mã nào nhanh hơn?

if (obj is ClassA) {}

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

Chỉnh sửa: Tôi biết rằng họ không làm điều tương tự.


1
Đã trả lời một câu hỏi tương tự ở đây: stackoverflow.com/questions/57701/ từ
swilliams

Câu trả lời:


167

Điều này sẽ trả lời câu hỏi đó, và sau đó một số.

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

(Hãy lưu ý rằng họ không làm điều tương tự)


1
+1: Trước đây tôi đã tự hỏi tại sao trình biên dịch C # không biên dịch typeof(string).TypeHandletheo lệnh ldtokenCIL, nhưng có vẻ như CLR quan tâm đến nó trong JIT. Nó vẫn cần thêm một vài opcodes nhưng đó là một ứng dụng tối ưu hóa tổng quát hơn.
Sam Harwell

2
Đọc highlogics.blogspot.ca / 2013/09 / cũng vậy - họ kiểm tra lại các khung khác nhau và x86 so với x64 với các kết quả khác nhau.
CAD bloke

1
Xin lưu ý điều này chỉ đúng với các loại tham khảo. Và sự khác biệt tốc độ không đáng kể. Đưa ra hình phạt đấm bốc trong trường hợp các loại giá trị cho GetType, isluôn luôn là một lựa chọn an toàn hơn khi có liên quan đến hiệu suất. Tất nhiên họ làm những việc khác nhau.
nawfal

Nếu bạn đặt nó trong Resharper, bạn nên đổi nó thành "is"!
Rob Sedgwick

@nawfal, ban đầu tôi nghĩ quan điểm của bạn về hình phạt đấm bốc có ý nghĩa đối với các loại cấu trúc, nhưng cho rằng chúng tôi đang thử nghiệm một object obj;biến, không phải nó đã được đóng hộp khi điều này có xu hướng được thử nghiệm? Có trường hợp nào bạn cần kiểm tra loại của một cái gì đó và nó chưa được đóng hộp như một đối tượng?
Rob Parker

193

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

ischo bạn biết nếu đối tượng thực hiện ClassAbất cứ nơi nào trong kiểu thừa kế của nó. GetType()cho bạn biết về loại có nguồn gốc nhất.

Không giống nhau.


7
Điều đó không quan trọng, vì trong trường hợp của tôi, tôi khẳng định họ sẽ trả lại kết quả tương tự.
ilitrite

37
@ [ilitirit]: họ trả lại kết quả tương tự ngay bây giờ, nhưng nếu bạn thêm một lớp con sau thì họ sẽ không
Steven A. Lowe

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

9
Các lớp học của tôi được niêm phong.
ilitrite

26

Họ không làm điều tương tự. Cái đầu tiên hoạt động nếu obj thuộc loại ClassA hoặc của một số lớp con 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 thứ bậc của 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 khảo trong là vs loại .


1
@amitjha Tôi hơi lo ngại rằng vì bài kiểm tra đó được thực hiện dưới Mono nên 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 đầu 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 của các hoạt động làm những việc khác nhau tùy thuộc vào loại dường như là một bài tập vô giá trị. Sử dụng thao tác phù hợp với hành vi bạn cần, không phải là hoạt động "nhanh hơn"
tvanfosson

16

Tôi đã làm một số điểm chuẩn trong đó họ làm tương tự - các loại 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 hàm chung để kiểm tra các loại chung:

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ũng đã thử các loại tùy chỉnh và kết quả phù hợp:

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

Sự suy luận:

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

  2. Trên một đối tượng, GetTypenhanh hơn, nhưng rất ít.

  3. Trên loại chung, nếu Tclass, thì isnhanh hơn nhiều. Nếu Tstruct, thì isnhanh hơn nhiều GetTypenhưng typeof(T)nhanh hơn cả hai. Trong trường hợp Ttồn tại class, 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 objectví dụ, sử dụng GetType. Nếu bạn có một loại chung class, sử dụng is. Nếu bạn có một loại chung struct, 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 luôn nhất quán với một kiểu (đối với loại kín), hãy sử dụng is..


1
Trong thực tế, không quan tâm chút nào. Sử dụng những gì có ý nghĩa nhất.
nawfal
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.