การตรวจสอบประเภท: typeof, GetType หรือเป็น?

ฉันเคยเห็นคนจำนวนมากใช้รหัสต่อไปนี้:

Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

แต่ฉันรู้ว่าคุณก็ทำสิ่งนี้ได้เช่นกัน:

if (obj1.GetType() == typeof(int))
    // Some code here

หรือสิ่งนี้:

if (obj1 is int)
    // Some code here

โดยส่วนตัวแล้วรู้สึกว่าอันสุดท้ายสะอาดที่สุดแต่ขาดอะไรไปหรือเปล่าคะ? ตัวไหนน่าใช้ที่สุดครับ หรือเป็นความชอบส่วนตัวครับ?


person jasonh    schedule 11.06.2009    source แหล่งที่มา
comment
อย่าลืมas!   -  person RCIX    schedule 08.10.2009
comment
as ไม่ใช่การตรวจสอบประเภทจริงๆ นะ...   -  person jasonh    schedule 08.10.2009
comment
as เป็นรูปแบบหนึ่งของการตรวจสอบประเภทอย่างแน่นอน มากพอๆ กับ is ที่เป็น! โดยจะใช้ is เบื้องหลังอย่างมีประสิทธิภาพ และใช้ทั่วทั้ง MSDN ในตำแหน่งที่ปรับปรุงความสะอาดของโค้ดเทียบกับ is แทนที่จะตรวจสอบ is ก่อน การเรียก as จะสร้างตัวแปรที่พิมพ์ไว้ซึ่งพร้อมใช้งาน: ถ้าเป็น null ให้ตอบสนองอย่างเหมาะสม มิฉะนั้นให้ดำเนินการต่อ แน่นอนสิ่งที่ฉันได้เห็นและใช้ไม่น้อย   -  person Zaccone    schedule 20.08.2014
comment
มีความแตกต่างด้านประสิทธิภาพที่สำคัญสำหรับ as/is (ครอบคลุมอยู่ใน stackoverflow.com/a/27813381/477420) โดยถือว่า ความหมายทำงานสำหรับกรณีของคุณ   -  person Alexei Levenkov    schedule 07.01.2015
comment
@samusarin มันไม่ใช้การสะท้อน วิธีการ GetType ที่คุณเชื่อมโยงอยู่ใน System.Reflection.Assembly -- วิธีการที่แตกต่างไปจากเดิมอย่างสิ้นเชิงและไม่เกี่ยวข้องกับที่นี่   -  person Kirk Woll    schedule 11.08.2017
comment
ฉันคิดว่า typeof(obj1) เป็นข้อผิดพลาดทางไวยากรณ์ ฉันคิดว่าคุณหมายถึง Type t = obj1.GetType();   -  person LongChalk    schedule 12.03.2019
comment
ฉันคิดว่าสิ่งที่ RCIC หมายถึงคือการตรวจสอบประเภทนั้นมักจะตามมาด้วยการร่ายและในกรณีเช่นนี้สามารถบันทึกการตรวจสอบประเภท (เช่นคือ) ได้: var castedType = otherType as CastedType; if (castedType != null) { ดำเนินการโดยใช้วัตถุประเภท CastedType };   -  person user3285954    schedule 15.03.2020


คำตอบ (14)


ทั้งหมดมีความแตกต่างกัน

  • typeof ใช้ชื่อประเภท (ซึ่งคุณระบุ ณ เวลาคอมไพล์)
  • GetType รับประเภทรันไทม์ของอินสแตนซ์
  • is คืนค่าเป็นจริงหากอินสแตนซ์อยู่ในแผนผังการสืบทอด

ตัวอย่าง

class Animal { } 
class Dog : Animal { }

void PrintTypes(Animal a) { 
    Console.WriteLine(a.GetType() == typeof(Animal)); // false 
    Console.WriteLine(a is Animal);                   // true 
    Console.WriteLine(a.GetType() == typeof(Dog));    // true
    Console.WriteLine(a is Dog);                      // true 
}

Dog spot = new Dog(); 
PrintTypes(spot);

แล้วtypeof(T)ล่ะ? ได้รับการแก้ไขในเวลารวบรวมด้วยหรือไม่

ใช่. T จะเป็นประเภทของนิพจน์เสมอ โปรดจำไว้ว่า วิธีการทั่วไปนั้นเป็นวิธีการทั้งหมดที่มีประเภทที่เหมาะสม ตัวอย่าง:

string Foo<T>(T parameter) { return typeof(T).Name; }

Animal probably_a_dog = new Dog();
Dog    definitely_a_dog = new Dog();

Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.

Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal". 
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
person Jimmy    schedule 11.06.2009
comment
อ่า ถ้าฉันมีคลาส Ford ที่มาจาก Car และอินสแตนซ์ของ Ford การตรวจสอบว่าเป็น Car บนอินสแตนซ์นั้นจะเป็นจริง มีเหตุผล! - person jasonh; 11.06.2009
comment
เพื่อชี้แจงให้กระจ่าง ฉันทราบเรื่องนั้นแล้ว แต่ฉันแสดงความคิดเห็นก่อนที่คุณจะเพิ่มตัวอย่างโค้ด ฉันต้องการลองเพิ่มความชัดเจนของภาษาอังกฤษให้กับคำตอบที่ยอดเยี่ยมอยู่แล้วของคุณ - person jasonh; 11.06.2009
comment
@Shimmy หาก typeof ได้รับการประเมิน ณ เวลาคอมไพล์และ GetType() ได้รับการประเมิน ณ รันไทม์ ก็สมเหตุสมผลแล้วที่ GetType() จะได้รับประสิทธิภาพเล็กน้อย - person Cedric Mamo; 10.12.2012
comment
แล้ว new Dog().GetType() คือ Animal หรือ typeof(Dog) คือ Animal มันแค่ให้คำเตือนไม่ใช่ข้อผิดพลาด? - person Prerak K; 07.05.2014
comment
@PrerakK new Dog().GetType() is Animal ส่งคืน false (และเวอร์ชันอื่นของคุณด้วย) เนื่องจาก .GetType() ส่งคืนวัตถุประเภท Type และ Type ไม่ใช่ Animal - person Maarten; 07.11.2014
comment
โดยทั่วไปแล้ว เมื่อคุณใช้ is หากทราบผลลัพธ์ (อย่างใดอย่างหนึ่ง true หรือ false) ณ เวลาคอมไพล์ คุณจะได้รับคำเตือนเวลาคอมไพล์ ซึ่งหมายความว่าคุณควรเปลี่ยนรหัสของคุณ! ตัวอย่างที่ 1: void M(Dog d) { var test = d is System.Exception; } จะเห็นได้ในเวลาคอมไพล์ว่าการอ้างอิง null หรืออินสแตนซ์ของ Dog ไม่สามารถเป็นอินสแตนซ์ของ System.Exception ได้ เนื่องจากประเภทที่เกี่ยวข้องคือประเภท class และแต่ละ class สามารถมีคลาสฐานโดยตรงได้เพียงคลาสเดียวเท่านั้น ตัวอย่างที่ 2: void M(int i) { var test = i is IConvertible; } จะเห็นได้ว่าในเวลาคอมไพล์ว่าสิ่งนี้เป็นจริงเสมอ (i ไม่เคยเป็นโมฆะ) - person Jeppe Stig Nielsen; 10.01.2017
comment
ฉันเห็นตัวอย่างของคุณใช้งานได้ แต่ดูเหมือนว่าจะล้มเหลวเมื่อการสืบทอดเป็น Object to Int32... พารามิเตอร์คือ Object ฉันกำลังขอให้พารามิเตอร์เป็น Int32 = false ซึ่งควรจะเป็นจริง - person Yogurtu; 09.01.2018
comment
สวัสดี @Yogurtu test(Object o) { return o is Int32; } จะกลับมาเป็น true สำหรับ test(10) - person Jimmy; 09.01.2018
comment
หัวข้อ Reflections และวิธีการเหล่านี้มีประโยชน์มากและในขณะเดียวกันก็ซับซ้อนเล็กน้อยและจำเป็นต้องศึกษาและทำงานในสาขานี้เพิ่มเติม - person elnaz jangi; 12.06.2020

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

มีตัวเลือกที่สี่ที่คุณยังไม่ได้พิจารณา (โดยเฉพาะถ้าคุณจะโยนวัตถุให้เป็นประเภทที่คุณพบเช่นกัน); นั่นคือการใช้ as

Foo foo = obj as Foo;

if (foo != null)
    // your code here

สิ่งนี้ใช้เพียง หนึ่ง คาสต์ โดยที่วิธีนี้:

if (obj is Foo)
    Foo foo = (Foo)obj;

ต้องการ สอง.

อัปเดต (มกราคม 2020):

  • ตั้งแต่ C# 7+ ตอนนี้คุณสามารถส่งแบบอินไลน์ได้แล้ว ดังนั้นวิธีการ 'เป็น' ก็สามารถทำได้ในการส่งครั้งเดียวเช่นกัน

ตัวอย่าง:

if(obj is Foo newLocalFoo)
{
    // For example, you can now reference 'newLocalFoo' in this local scope
    Console.WriteLine(newLocalFoo);
}
person Andrew Hare    schedule 11.06.2009
comment
ด้วยการเปลี่ยนแปลงใน .NET 4 is ยังคงแสดงอยู่หรือไม่ - person ahsteele; 22.03.2013
comment
คำตอบนี้ถูกต้องหรือไม่? จริงหรือไม่ที่คุณสามารถส่งอินสแตนซ์ไปที่ typeof() ได้จริงหรือ? ประสบการณ์ของฉันไม่ใช่ แต่ฉันเดาว่าโดยทั่วไปแล้วการตรวจสอบอินสแตนซ์อาจต้องเกิดขึ้นที่รันไทม์ ในขณะที่การตรวจสอบคลาสควรจะทำได้ในเวลาคอมไพล์ - person Jon Coombs; 08.10.2013
comment
@jon (4 ปีหลังจากคำถามของคุณ) ไม่ คุณไม่สามารถส่งอินสแตนซ์ไปที่ typeof() และคำตอบนี้ไม่แนะนำให้คุณทำได้ คุณผ่านประเภทแทน เช่น typeof(string) ใช้งานได้ typeof("foo") ไม่ผ่าน - person Abel; 20.09.2017
comment
ฉันไม่เชื่อว่า is ดำเนินการเช่นนั้น แต่เป็นการดำเนินการพิเศษใน IL - person abatishchev; 22.10.2018
comment
ตอนนี้เราทำได้แล้ว if (obj is Foo foo) { /* use foo here */ } - person Ivan García Topete; 17.04.2019
comment
ไม่ค่อยมีกรณีใดที่จะใช้เหมือนกับการแคสต์ และในกรณีส่วนใหญ่ คุณจะต้องแคสต์ตัวแปรอยู่ดี - จริงๆ แล้วมีกรณีการใช้งานที่ถูกต้องมากของ is ดูคำตอบของ JoelC คุณสามารถใช้คือเพื่อพิมพ์ตรวจสอบและส่งแบบอินไลน์ มันเรียบร้อยมาก แน่นอนว่าสิ่งนี้มีเฉพาะใน C#7 ขึ้นไปฉันเชื่อว่า - person Colm Bhandal; 14.08.2019

1.

Type t = typeof(obj1);
if (t == typeof(int))

สิ่งนี้ผิดกฎหมาย เนื่องจาก typeof ใช้ได้กับประเภทเท่านั้น ไม่ใช่กับตัวแปร ฉันคิดว่า obj1 เป็นตัวแปร ดังนั้น ด้วยวิธีนี้ typeof จึงเป็นแบบคงที่ และทำงานในเวลาคอมไพล์แทนที่จะเป็นรันไทม์

2.

if (obj1.GetType() == typeof(int))

นี่คือ true ถ้า obj1 เป็นประเภท int ทุกประการ ถ้า obj1 มาจาก int เงื่อนไข if จะเป็น false

3.

if (obj1 is int)

นี่คือ true หาก obj1 เป็น int หรือหากมาจากคลาสที่เรียกว่า int หรือหากใช้อินเทอร์เฟซที่เรียกว่า int

person Scott Langham    schedule 11.06.2009
comment
คิดถึงค.1 ถูกต้องครับ แต่ฉันได้เห็นมันในตัวอย่างโค้ดหลายตัวอย่างที่นี่ ควรเป็นประเภท t = obj1.GetType(); - person jasonh; 11.06.2009
comment
ใช่ ฉันก็คิดอย่างนั้น typeof(obj1) ไม่คอมไพล์เมื่อฉันลอง - person Scott Langham; 11.06.2009
comment
เป็นไปไม่ได้ที่จะได้มาจาก System.Int32 หรือค่าประเภทอื่นใน C# - person reggaeguitar; 04.12.2014
comment
คุณบอกได้ไหมว่าอะไรจะเป็น typeof(typeof(system.int32)) - person Sana; 27.06.2018
comment
@Sana ทำไมคุณไม่ลอง :) ฉันคิดว่าแม้ว่าคุณจะได้รับอินสแตนซ์ของ System.Type ที่แสดงถึงประเภท System.Type กลับคืนมา! เอกสารประกอบสำหรับ typeof อยู่ที่นี่: docs.microsoft.com/ en-us/dotnet/csharp/ภาษาอ้างอิง/ - person Scott Langham; 02.07.2018

Type t = typeof(obj1);
if (t == typeof(int))
    // Some code here

นี่เป็นข้อผิดพลาด ตัวดำเนินการ typeof ใน C# สามารถรับได้เฉพาะชื่อประเภทเท่านั้น ไม่สามารถรับวัตถุได้

if (obj1.GetType() == typeof(int))
    // Some code here

สิ่งนี้จะได้ผล แต่อาจไม่เป็นไปตามที่คุณคาดหวัง สำหรับประเภทค่า ตามที่คุณแสดงไว้ที่นี่ ก็ยอมรับได้ แต่สำหรับประเภทการอ้างอิง จะส่งคืนค่าเป็นจริงก็ต่อเมื่อประเภทนั้นเป็นประเภท เหมือนกันทุกประการ ไม่ใช่อย่างอื่นในลำดับชั้นการสืบทอด ตัวอย่างเช่น:

class Animal{}
class Dog : Animal{}

static void Foo(){
    object o = new Dog();

    if(o.GetType() == typeof(Animal))
        Console.WriteLine("o is an animal");
    Console.WriteLine("o is something else");
}

สิ่งนี้จะพิมพ์ "o is something else" เนื่องจากประเภทของ o คือ Dog ไม่ใช่ Animal อย่างไรก็ตาม คุณสามารถทำให้สิ่งนี้สำเร็จได้ หากคุณใช้เมธอด IsAssignableFrom ของคลาส Type

if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
    Console.WriteLine("o is an animal");

เทคนิคนี้ยังคงทิ้งปัญหาสำคัญไว้ หากตัวแปรของคุณเป็นโมฆะ การเรียก GetType() จะส่ง NullReferenceException เพื่อให้ทำงานได้อย่างถูกต้อง คุณจะต้องทำดังนี้

if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
    Console.WriteLine("o is an animal");

ด้วยเหตุนี้ คุณจึงมีพฤติกรรมที่เทียบเท่ากับคำหลัก is ดังนั้น หากนี่เป็นพฤติกรรมที่คุณต้องการ คุณควรใช้คีย์เวิร์ด is ซึ่งสามารถอ่านได้ง่ายและมีประสิทธิภาพมากกว่า

if(o is Animal)
    Console.WriteLine("o is an animal");

อย่างไรก็ตาม ในกรณีส่วนใหญ่ คำหลัก is ยังคงไม่ใช่สิ่งที่คุณต้องการจริงๆ เนื่องจากโดยปกติแล้ว การทราบว่าออบเจ็กต์นั้นมีประเภทใดประเภทหนึ่งนั้นไม่เพียงพอ โดยปกติแล้ว คุณต้องการใช้ออบเจ็กต์นั้นเป็นอินสแตนซ์ประเภทนั้นจริงๆ ซึ่งต้องมีการส่งออบเจ็กต์ด้วย ดังนั้นคุณอาจพบว่าตัวเองกำลังเขียนโค้ดดังนี้:

if(o is Animal)
    ((Animal)o).Speak();

แต่นั่นทำให้ CLR ตรวจสอบประเภทของวัตถุมากถึงสองครั้ง มันจะตรวจสอบหนึ่งครั้งเพื่อให้เป็นไปตามตัวดำเนินการ is และหาก o เป็น Animal จริงๆ เราจะทำการตรวจสอบอีกครั้งเพื่อตรวจสอบความถูกต้องของการส่ง

การทำเช่นนี้มีประสิทธิภาพมากกว่าแทน:

Animal a = o as Animal;
if(a != null)
    a.Speak();

ตัวดำเนินการ as เป็นตัวส่งที่จะไม่ทำให้เกิดข้อยกเว้นหากล้มเหลว แต่จะส่งคืน null แทน ด้วยวิธีนี้ CLR จะตรวจสอบประเภทของออบเจ็กต์เพียงครั้งเดียว และหลังจากนั้น เราก็ต้องทำการตรวจสอบแบบ null ซึ่งมีประสิทธิภาพมากกว่า

แต่ระวัง: หลายคนติดกับดักด้วย as เนื่องจากไม่มีข้อยกเว้น บางคนจึงคิดว่ามันเป็นนักแสดงที่ "ปลอดภัย" และพวกเขาใช้มันโดยเฉพาะ โดยเลี่ยงการร่ายแบบปกติ สิ่งนี้นำไปสู่ข้อผิดพลาดเช่นนี้:

(o as Animal).Speak();

ในกรณีนี้ นักพัฒนาเห็นได้ชัดว่าสมมติว่า o จะเสมอเป็น Animal และตราบใดที่สมมติฐานถูกต้อง ทุกอย่างก็ใช้ได้ดี แต่ถ้าพวกเขาผิด สิ่งที่พวกเขาจะได้คือ NullReferenceException หากใช้นักแสดงปกติ พวกเขาจะได้รับ InvalidCastException แทน ซึ่งจะทำให้ระบุปัญหาได้ถูกต้องมากขึ้น

บางครั้งข้อผิดพลาดนี้อาจพบได้ยาก:

class Foo{
    readonly Animal animal;

    public Foo(object o){
        animal = o as Animal;
    }

    public void Interact(){
        animal.Speak();
    }
}

นี่เป็นอีกกรณีที่นักพัฒนาคาดหวังอย่างชัดเจนว่า o จะเป็น Animal ทุกครั้ง แต่สิ่งนี้ไม่ชัดเจนในตัวสร้างที่ซึ่งใช้ as คาสต์ จะไม่ชัดเจนจนกว่าคุณจะไปถึงวิธี Interact โดยที่ฟิลด์ animal คาดว่าจะได้รับการกำหนดในเชิงบวก ในกรณีนี้ ไม่เพียงแต่คุณจะพบกับข้อยกเว้นที่ทำให้เข้าใจผิดเท่านั้น แต่ยังไม่ถูกโยนทิ้งจนกว่าจะช้ากว่าตอนที่เกิดข้อผิดพลาดจริงมาก

สรุป:

  • หากคุณต้องการทราบว่าออบเจ็กต์เป็นประเภทใดหรือไม่ ให้ใช้ is

  • หากคุณต้องการให้วัตถุเป็นอินสแตนซ์ประเภทใดประเภทหนึ่ง แต่คุณไม่ทราบแน่ชัดว่าวัตถุนั้นจะเป็นประเภทนั้น ให้ใช้ as และตรวจสอบหา null

  • หากคุณต้องการให้วัตถุเป็นอินสแตนซ์ประเภทใดประเภทหนึ่ง และวัตถุนั้นควรจะเป็นประเภทนั้น ให้ใช้การส่งแบบปกติ

person P Daddy    schedule 11.06.2009
comment
เกิดอะไรขึ้นกับสิ่งนี้ if(o is Animal) ((Animal)o).Speak(); ? คุณช่วยกรุณาให้รายละเอียดเพิ่มเติมได้ไหม? - person Emil; 11.01.2017
comment
@batmaci: มันอยู่ในคำตอบ - มันทำให้เกิดการตรวจสอบสองประเภท ครั้งแรกคือ o is Animal ซึ่งต้องใช้ CLR เพื่อตรวจสอบว่าประเภทของตัวแปร o เป็น Animal หรือไม่ ครั้งที่สองที่ตรวจสอบคือเมื่อมีการแปลงคำสั่ง ((Animal)o).Speak() แทนที่จะตรวจสอบสองครั้ง ให้ตรวจสอบอีกครั้งโดยใช้ as - person siride; 28.07.2018
comment
ฉันพบว่านี่เป็นคำอธิบายที่ยอดเยี่ยมมาก ขอบคุณสำหรับการชี้แจง! - person Paul Efford; 29.11.2019

หากคุณใช้ C# 7 ถึงเวลาอัปเดตคำตอบที่ยอดเยี่ยมของ Andrew Hare การจับคู่รูปแบบ ได้แนะนำทางลัดที่ดีที่ให้ตัวแปรที่พิมพ์แก่เรา ภายในบริบทของคำสั่ง if โดยไม่ต้องมีการประกาศ/แสดงและตรวจสอบแยกต่างหาก:

if (obj1 is int integerValue)
{
    integerValue++;
}

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

Button button = obj1 as Button;
if (button != null)
{
    // do stuff...
    return;
}
TextBox text = obj1 as TextBox;
if (text != null)
{
    // do stuff...
    return;
}
Label label = obj1 as Label;
if (label != null)
{
    // do stuff...
    return;
}
// ... and so on

การหลีกเลี่ยงไม่ให้โค้ดนี้เล็กลงให้มากที่สุดเท่าที่จะเป็นไปได้ รวมทั้งหลีกเลี่ยงการใช้ออบเจ็กต์เดียวกันซ้ำซ้อนทำให้ฉันกังวลอยู่เสมอ ข้อมูลข้างต้นได้รับการบีบอัดอย่างดีโดยมีรูปแบบที่ตรงกับสิ่งต่อไปนี้:

switch (obj1)
{
    case Button button:
        // do stuff...
        break;
    case TextBox text:
        // do stuff...
        break;
    case Label label:
        // do stuff...
        break;
    // and so on...
}

แก้ไข: อัปเดตวิธีการใหม่ที่ยาวขึ้นเพื่อใช้สวิตช์ตามความคิดเห็นของ Palec

person JoelC    schedule 01.02.2018

ฉันมีคุณสมบัติ Type ที่จะเปรียบเทียบและไม่สามารถใช้ is (เช่น my_type is _BaseTypetoLookFor) แต่ฉันสามารถใช้สิ่งเหล่านี้ได้:

base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);

โปรดสังเกตว่า IsInstanceOfType และ IsAssignableFrom ส่งคืน true เมื่อเปรียบเทียบประเภทเดียวกัน โดยที่ IsSubClassOf จะส่งกลับ false และ IsSubclassOf ใช้งานไม่ได้บนอินเทอร์เฟซ ซึ่งอีก 2 ตัวทำงาน (โปรดดู คำถามและคำตอบนี้)

public class Animal {}
public interface ITrainable {}
public class Dog : Animal, ITrainable{}

Animal dog = new Dog();

typeof(Animal).IsInstanceOfType(dog);     // true
typeof(Dog).IsInstanceOfType(dog);        // true
typeof(ITrainable).IsInstanceOfType(dog); // true

typeof(Animal).IsAssignableFrom(dog.GetType());      // true
typeof(Dog).IsAssignableFrom(dog.GetType());         // true
typeof(ITrainable).IsAssignableFrom(dog.GetType()); // true

dog.GetType().IsSubclassOf(typeof(Animal));            // true
dog.GetType().IsSubclassOf(typeof(Dog));               // false
dog.GetType().IsSubclassOf(typeof(ITrainable)); // false
person Yahoo Serious    schedule 15.05.2012

ฉันชอบ คือ

ที่กล่าวว่า หากคุณใช้ is คุณมีแนวโน้มที่จะ ไม่ ใช้การสืบทอดอย่างถูกต้อง

สมมติว่าบุคคลนั้น: เอนทิตี และสัตว์นั้น: เอนทิตี Feed เป็นวิธีการเสมือนใน Entity (เพื่อทำให้ Neil มีความสุข)

class Person
{
  // A Person should be able to Feed
  // another Entity, but they way he feeds
  // each is different
  public override void Feed( Entity e )
  {
    if( e is Person )
    {
      // feed me
    }
    else if( e is Animal )
    {
      // ruff
    }
  }
}

ค่อนข้าง

class Person
{
  public override void Feed( Person p )
  {
    // feed the person
  }
  public override void Feed( Animal a )
  {
    // feed the animal
  }
}
person bobobobo    schedule 11.06.2009
comment
จริงอยู่ ฉันจะไม่ทำอย่างแรกเลย เพราะรู้ว่าบุคคลนั้นมาจากสัตว์ - person jasonh; 11.06.2009
comment
อย่างหลังไม่ได้ใช้มรดกจริงๆเช่นกัน Foo ควรเป็นวิธีการเสมือนของ Entity ที่ถูกแทนที่ใน Person และ Animal - person Neil Williams; 11.06.2009
comment
@bobobobo ฉันคิดว่าคุณหมายถึงการโอเวอร์โหลดไม่ใช่การสืบทอด - person lc.; 11.06.2009
comment
@lc: ไม่ ฉันหมายถึงมรดก ตัวอย่างแรกเป็นวิธีที่ไม่ถูกต้อง (ใช้ is) เพื่อให้เกิดพฤติกรรมที่แตกต่างออกไป ตัวอย่างที่สองใช้การโอเวอร์โหลดใช่ แต่หลีกเลี่ยงการใช้ เป็น - person bobobobo; 11.06.2009
comment
ข้อดีที่โดยทั่วไปแล้วการใช้คีย์เวิร์ด 'is' ถือเป็นตัวเลือกการออกแบบที่ไม่ดี อย่างไรก็ตาม โซลูชันที่ให้มาไม่ได้แก้ไขการออกแบบ แต่เพียงเปลี่ยนวิธีการนำไปใช้ - person ebrown; 12.06.2009
comment
ปัญหาของตัวอย่างคือมันไม่สามารถปรับขนาดได้ หากคุณเพิ่มเอนทิตีใหม่ที่จำเป็นต้องกิน (เช่น แมลงหรือสัตว์ประหลาด) คุณจะต้องเพิ่มวิธีการใหม่ในคลาส Entity จากนั้นแทนที่มันในคลาสย่อยที่จะป้อนมัน สิ่งนี้ไม่เป็นที่นิยมไปกว่ารายการถ้า (เอนทิตีคือ X) อย่างอื่นถ้า (เอนทิตีคือ Y)... สิ่งนี้ละเมิด LSP และ OCP การสืบทอดอาจไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด อาจต้องการการมอบหมายรูปแบบใดรูปแบบหนึ่ง - person ebrown; 12.06.2009

ฉันเชื่อว่าอันสุดท้ายยังดูที่มรดกด้วย (เช่น Dog is Animal == true) ซึ่งดีกว่าในกรณีส่วนใหญ่

person StriplingWarrior    schedule 11.06.2009

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

person AllenG    schedule 11.06.2009
comment
จุดดี. ฉันลืมที่จะพูดถึงว่าฉันได้รับคำถามนี้หลังจากดูคำตอบหลายข้อที่ใช้คำสั่ง if เพื่อตรวจสอบประเภท - person jasonh; 11.06.2009

อันสุดท้ายสะอาดกว่า ชัดเจนกว่า และยังตรวจสอบประเภทย่อยด้วย คนอื่นๆ ไม่ได้ตรวจสอบความหลากหลาย

person thecoop    schedule 11.06.2009

ใช้เพื่อรับวัตถุ System.Type สำหรับชนิด นิพจน์ typeof มีรูปแบบดังนี้:

System.Type type = typeof(int);

Example:

    public class ExampleClass
    {
       public int sampleMember;
       public void SampleMethod() {}

       static void Main()
       {
          Type t = typeof(ExampleClass);
          // Alternatively, you could use
          // ExampleClass obj = new ExampleClass();
          // Type t = obj.GetType();

          Console.WriteLine("Methods:");
          System.Reflection.MethodInfo[] methodInfo = t.GetMethods();

          foreach (System.Reflection.MethodInfo mInfo in methodInfo)
             Console.WriteLine(mInfo.ToString());

          Console.WriteLine("Members:");
          System.Reflection.MemberInfo[] memberInfo = t.GetMembers();

          foreach (System.Reflection.MemberInfo mInfo in memberInfo)
             Console.WriteLine(mInfo.ToString());
       }
    }
    /*
     Output:
        Methods:
        Void SampleMethod()
        System.String ToString()
        Boolean Equals(System.Object)
        Int32 GetHashCode()
        System.Type GetType()
        Members:
        Void SampleMethod()
        System.String ToString()
        Boolean Equals(System.Object)
        Int32 GetHashCode()
        System.Type GetType()
        Void .ctor()
        Int32 sampleMember
    */

ตัวอย่างนี้ใช้วิธีการ GetType เพื่อกำหนดชนิดที่ใช้ในการเก็บผลลัพธ์ของการคำนวณตัวเลข ขึ้นอยู่กับข้อกำหนดในการจัดเก็บของหมายเลขผลลัพธ์

    class GetTypeTest
    {
        static void Main()
        {
            int radius = 3;
            Console.WriteLine("Area = {0}", radius * radius * Math.PI);
            Console.WriteLine("The type is {0}",
                              (radius * radius * Math.PI).GetType()
            );
        }
    }
    /*
    Output:
    Area = 28.2743338823081
    The type is System.Double
    */
person Muhammad Awais    schedule 14.04.2016

คุณสามารถใช้ตัวดำเนินการ "typeof()" ใน C# ได้ แต่คุณต้องเรียกเนมสเปซโดยใช้ System.IO คุณต้องใช้คีย์เวิร์ด "is" หากคุณต้องการตรวจสอบประเภท

person androidrill    schedule 03.04.2014
comment
typeof ไม่ได้ถูกกำหนดไว้ในเนมสเปซ แต่เป็นคำหลัก System.IOไม่เกี่ยวอะไรกับเรื่องนี้ - person Arturo Torres Sánchez; 18.09.2015

ประเภทการทดสอบประสิทธิภาพ () กับ GetType ():

using System;
namespace ConsoleApplication1
    {
    class Program
    {
        enum TestEnum { E1, E2, E3 }
        static void Main(string[] args)
        {
            {
                var start = DateTime.UtcNow;
                for (var i = 0; i < 1000000000; i++)
                    Test1(TestEnum.E2);
                Console.WriteLine(DateTime.UtcNow - start);
            }
            {
                var start = DateTime.UtcNow;
                for (var i = 0; i < 1000000000; i++)
                    Test2(TestEnum.E2);
                Console.WriteLine(DateTime.UtcNow - start);
            }
            Console.ReadLine();
        }
        static Type Test1<T>(T value) => typeof(T);
        static Type Test2(object value) => value.GetType();
    }
}

ผลลัพธ์ในโหมดแก้ไขข้อบกพร่อง:

00:00:08.4096636
00:00:10.8570657

ผลลัพธ์ในโหมดเผยแพร่:

00:00:02.3799048
00:00:07.1797128
person Alexander Vasilyev    schedule 03.08.2015
comment
เราไม่ควรใช้ DateTime.UtcNow สำหรับการวัดประสิทธิภาพ ด้วยรหัสของคุณ แต่ด้วยคลาส Stopwatch ฉันได้ผลลัพธ์ที่ตรงกันข้ามกับโหมด Debug อย่างต่อเนื่อง UseTypeOf: 00:00:14.5074469 UseGetType: 00:00:10.5799534 โหมดวางจำหน่ายก็เหมือนเดิมตามที่คาดไว้ - person Alexey Shcherbak; 25.11.2015
comment
@AlexeyShcherbak ความแตกต่างระหว่าง Stopwatch และ DateTime ตอนนี้ต้องไม่เกิน 10-20 ms ตรวจสอบรหัสของคุณอีกครั้ง และฉันไม่สนใจเรื่องมิลลิวินาทีในการทดสอบของฉัน รหัสของฉันจะเป็นโค้ดหลายบรรทัดอีกต่อไปด้วย Stopwatch - person Alexander Vasilyev; 25.11.2015
comment
โดยทั่วไปถือเป็นแนวปฏิบัติที่ไม่ดี ไม่ใช่ในกรณีเฉพาะของคุณ - person Alexey Shcherbak; 25.11.2015
comment
@AlexanderVasilyev จำนวนบรรทัดของโค้ดไม่ควรใช้เป็นข้อโต้แย้งในการทำสิ่งที่ มีเอกสาร ที่ทำให้เข้าใจผิด ดังที่เห็นใน msdn.microsoft.com/ en-us/library/system.datetime(v=vs.110).aspx, DateTime ไม่ควรใช้หากคุณกังวลเกี่ยวกับเวลาที่ต่ำกว่า 100ms เนื่องจากจะใช้ระบบปฏิบัติการ กรอบเวลา. เมื่อเปรียบเทียบกับ Stopwatch ซึ่งใช้ Tick ของโปรเซสเซอร์ ความละเอียดที่ใช้โดย DateTime ใน Win7 อยู่ที่ 15 มิลลิวินาที - person Eric Wu; 06.03.2016

person    schedule
comment
โปรดแก้ไขด้วยข้อมูลเพิ่มเติม ไม่แนะนำให้ใช้รหัสเท่านั้นและลองใช้คำตอบนี้ เนื่องจากไม่มีเนื้อหาที่สามารถค้นหาได้ และไม่ได้อธิบายว่าเหตุใดจึงควรลองใช้คำตอบนี้ - person abarisone; 06.09.2016
comment
คำตอบของคุณไม่เกี่ยวข้องกับคำถาม - person menxin; 05.09.2019