เทียบกับ typeof


150

รหัสชิ้นใดเร็วกว่ากัน

if (obj is ClassA) {}

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

แก้ไข: ฉันทราบว่าพวกเขาไม่ได้ทำสิ่งเดียวกัน


1
ตอบคำถามที่คล้ายกันที่นี่: stackoverflow.com/questions/57701/…
swilliams

คำตอบ:


167

นี่ควรจะตอบคำถามนั้นแล้วก็มีบ้าง

บรรทัดที่สองif (obj.GetType() == typeof(ClassA)) {}นั้นเร็วกว่าสำหรับผู้ที่ไม่ต้องการอ่านบทความ

(โปรดระวังว่าพวกเขาไม่ได้ทำสิ่งเดียวกัน)


1
1: ในอดีตผมสงสัยว่าทำไม C # คอมไพเลอร์ไม่ได้รวบรวมtypeof(string).TypeHandleกับldtokenการเรียนการสอน CIL แต่ดูเหมือนว่า CLR ดูแลในร์ JIT มันยังใช้เวลาเพิ่ม opcodes เพียงไม่กี่ตัว
Sam Harwell

2
อ่านHigherlogics.blogspot.ca/2013/09/…ด้วย - พวกเขาทำการทดสอบเฟรมเวิร์กที่แตกต่างกันและ x86 vs x64 พร้อมผลลัพธ์ที่แตกต่างกันอย่างกว้างขวาง
CAD bloke

1
โปรดทราบว่านี่เป็นความจริงสำหรับประเภทการอ้างอิงเท่านั้น และความแตกต่างของความเร็วนั้นไม่สำคัญเท่าไหร่ ได้รับโทษมวยในกรณีของประเภทค่าสำหรับGetType, isมักจะเป็นทางเลือกที่ปลอดภัยเท่าที่ประสิทธิภาพการทำงานที่เป็นห่วง แน่นอนว่าพวกเขาทำสิ่งต่าง ๆ
nawfal

หากคุณใส่ไว้ใน Resharper แนะนำให้เปลี่ยนเป็น "is"!
Rob Sedgwick

@ นวฟัลฉันเริ่มคิดว่าจุดของคุณเกี่ยวกับการลงโทษมวยเหมาะสมสำหรับประเภท struct แต่เนื่องจากเรากำลังทดสอบobject obj;ตัวแปรมันไม่ได้บรรจุอยู่แล้วเมื่อสิ่งนี้มีแนวโน้มที่จะทดสอบ? มีกรณีที่คุณต้องการทดสอบประเภทของบางสิ่งบางอย่างและยังไม่ได้บรรจุเป็นวัตถุหรือไม่?
Rob Parker

193

มันสำคัญไหมที่เร็วกว่ากันถ้าพวกเขาไม่ทำแบบเดียวกัน? การเปรียบเทียบประสิทธิภาพของข้อความที่มีความหมายแตกต่างกันดูเหมือนเป็นความคิดที่ไม่ดี

isแจ้งให้คุณทราบว่าวัตถุดำเนินการตามClassAลำดับชั้นของวัตถุหรือไม่ GetType()บอกคุณเกี่ยวกับประเภทที่ได้มามากที่สุด

ไม่เหมือนกัน


7
มันเป็นเรื่องสำคัญเพราะในกรณีของฉันฉันมั่นใจว่าพวกเขากลับมาเหมือนเดิม
ilitirit

37
@ [ilitirit]: พวกเขากลับผลลัพธ์เดียวกันในตอนนี้ แต่ถ้าคุณเพิ่มคลาสย่อยในภายหลังพวกเขาจะไม่ได้
Steven A. Lowe

13
การเพิ่มประสิทธิภาพในขณะนี้จะทำให้โค้ดของคุณเปราะและยากต่อการบำรุงรักษา
ICR

9
ชั้นเรียนของฉันถูกปิดผนึก
ilitirit

26

พวกเขาไม่ทำสิ่งเดียวกัน อันแรกทำงานได้ถ้า obj เป็นประเภท ClassA หรือบางคลาสย่อยของ ClassA อันที่สองจะจับคู่กับวัตถุประเภท ClassA เท่านั้น อันที่สองจะเร็วขึ้นเนื่องจากไม่ต้องตรวจสอบลำดับชั้นของชั้นเรียน

สำหรับผู้ที่ต้องการทราบเหตุผล แต่ไม่ต้องการอ่านบทความที่อ้างถึง เป็น VS typeof


1
@amitjha ฉันกังวลเล็กน้อยว่าเพราะการทดสอบนั้นดำเนินการภายใต้ Mono ที่ไม่รวมการปรับให้เหมาะสมของ JIT ที่อ้างอิงในบทความ เนื่องจากบทความแสดงสิ่งที่ตรงกันข้ามในใจของฉันคำถามคือคำถามที่เปิดอยู่ ไม่ว่าในกรณีใดการเปรียบเทียบประสิทธิภาพของการปฏิบัติงานที่ทำในสิ่งที่แตกต่างกันไปขึ้นอยู่กับประเภทนั้น ๆ ใช้การดำเนินการที่ตรงกับพฤติกรรมที่คุณต้องการไม่ได้เป็นคนที่เป็น "เร็วขึ้น"
tvanfosson

16

ฉันทำการเปรียบเทียบที่พวกเขาทำเช่นเดียวกัน - ประเภทที่ปิดผนึก

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());

ฟังก์ชั่นทั่วไปในการทดสอบประเภททั่วไป:

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

ฉันลองใช้ประเภทที่กำหนดเองเช่นกันและผลลัพธ์ก็สอดคล้องกัน:

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());

และประเภท:

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

อนุมาน:

  1. การโทรGetTypeบนstructจะช้ากว่า GetTypeจะถูกกำหนดไว้ในobjectระดับที่ไม่สามารถแทนที่ในประเภทย่อยและทำให้structs GetTypeจำเป็นที่จะต้องได้รับการบรรจุอยู่ในกล่องจะถูกเรียกว่า

  2. ในอินสแตนซ์ของวัตถุGetTypeนั้นเร็วกว่า แต่มีขอบเขตน้อยมาก

  3. สำหรับประเภททั่วไปถ้าTเป็นclassแล้วisจะเร็วกว่ามาก ถ้าTเป็นstructเช่นนั้นisจะเร็วกว่าGetTypeแต่typeof(T)เร็วกว่ามาก ในกรณีที่มีTความเป็นอยู่class, ไม่น่าเชื่อถือตั้งแต่ที่แตกต่างกันจากชนิดพื้นฐานที่เกิดขึ้นจริงtypeof(T)t.GetType

ในระยะสั้นหากคุณมีตัวอย่างเช่นการใช้งานobject GetTypeหากคุณมีทั่วไปประเภทการใช้งานclass isหากคุณมีทั่วไปประเภทการใช้งานstruct หากคุณไม่แน่ใจว่าประเภททั่วไปเป็นประเภทการอ้างอิงหรือประเภทค่าใช้typeof(T) isหากคุณต้องการให้สอดคล้องกับสไตล์เดียวเสมอ (สำหรับประเภทที่ปิดผนึก) ให้ใช้is..


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