ทดสอบว่าวัตถุใช้ส่วนต่อประสานหรือไม่


355

อะไรคือวิธีที่ง่ายที่สุดในการทดสอบว่าวัตถุใช้อินเทอร์เฟซที่กำหนดใน C # หรือไม่ (ตอบคำถามนี้ ใน Java )

คำตอบ:


569
if (object is IBlah)

หรือ

IBlah myTest = originalObject as IBlah

if (myTest != null)

85
+1 อันที่สองนั้นดีกว่าเพราะคุณอาจจะต้องลงเอยด้วยการโยนครั้งแรกหลังจากนั้นก็ให้การปลดเปลื้องสองครั้ง ("คือ" และการร่ายที่ชัดเจน) ด้วยวิธีที่สองคุณเพียงครั้งเดียวเท่านั้น
แอนดรูกระต่าย

51
@Andrew: +1; เวลาอีกครั้งสำหรับการเชื่อมโยงไปยังบล็อกโพสต์คลาสสิกดับเบิลหล่อ AntiPattern โดยจูเลียน M Bucknall
Jeroen Wiert Pluimers

1
การเพิ่มประสิทธิภาพอาจไม่ทำให้คุณแคสต์สองครั้งในกรณีแรกใช่หรือไม่
BuZz

1
@Joreen ลิงก์นั้นพลาดไปหนึ่งจุดหากคุณทำงานกับโครงสร้างที่คุณไม่สามารถใช้ "เป็น" เพราะมันจะไม่ถือเป็นโมฆะซึ่งเป็นสิ่งที่ "เป็น" พยายามที่จะกลับมาในกรณีที่คุณต้องผ่านโมฆะ class like int? แม้ว่าจะไม่ใช่ปัญหาหากคุณทำงานที่ระดับอินเตอร์เฟสเท่านั้นเนื่องจากเป็นประเภทอ้างอิงเสมอ
MikeT

46
ตั้งแต่ C # 6.0:if (object is IBlah iblah) { iblah.SomeMethod(); }
Knelis

224

การใช้isหรือasโอเปอเรเตอร์เป็นวิธีที่ถูกต้องหากคุณรู้ว่าประเภทอินเตอร์เฟสในเวลารวบรวมและมีอินสแตนซ์ของประเภทที่คุณกำลังทดสอบ สิ่งที่ดูเหมือนไม่มีใครพูดถึงคือType.IsAssignableFrom:

if( typeof(IMyInterface).IsAssignableFrom(someOtherType) )
{
}

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


ฉันพยายามที่จะตรวจสอบว่าประเภทใช้การสร้างอินสแตนซ์ของ IList บ้าง ฉันใช้ "typeof (IList <>) IsAssignableFrom (someType)" แต่นั่นไม่ทำงาน
KeyboardDrummer

3
คุณน่าจะถามคำถามนี้ในคำถามอื่นดีกว่า หาก someType เป็นประเภทขององค์ประกอบรายการคุณอาจต้องการ typeof (IList <>) MakeGenericType (someType) หาก someType เป็นประเภทรายการคุณควรดูที่ Type.GetGenericArguments และ Type.GetGenericTypeDefinition
Andrew Kennan

ฉันใช้สิ่งนี้สำหรับการตรวจสอบประเภทในระบบปลั๊กอิน สามารถใช้ในสถานการณ์ที่ไม่มีอินสแตนซ์ของวัตถุอยู่ แต่ฉันใช้ทั้งสไตล์นี้และของโรเบิร์ตขึ้นอยู่กับสิ่งที่ฉันทำดังนั้นฉันจึงโหวตทั้งสองวิธี
James

นี่คือการแสดงความคิดเห็นเก่า แต่จะตอบคำถาม @ Steenreem ของการใช้งานโดยไม่ต้องtypeof(IList).IsAssignableFrom(someType) <>
saluce

วิธีนี้ใช้ได้กับตัวดำเนินการแปลงและถ้าเกี่ยวข้องกับ TypeConverters
Harald Coppoolse

22

สำหรับตัวอย่าง:

if (obj is IMyInterface) {}

สำหรับชั้นเรียน:

ตรวจสอบว่าtypeof(MyClass).GetInterfaces()มีส่วนต่อประสานหรือไม่


1
if (Array.IndexOf (typeof (MyClass) .GetInterfaces (), typeof (IMyInterface))! = -1) {... }
Constantin

2
หรือ: if (typeof (MyClass) .GetInterfaces (). ประกอบด้วย (typeof (IMyInterface))) {... }
Lance Fisher

17

หากคุณต้องการใช้วัตถุ typecasted หลังจากการตรวจสอบ:
ตั้งแต่ C # 7.0:

if (obj is IMyInterface myObj)

นี่คือเช่นเดียวกับ

IMyInterface myObj = obj as IMyInterface;
if (myObj != null)

ดูเอกสาร. NET: การจับคู่isรูปแบบที่มีรูปแบบ # Type


16

รูปแบบของคำตอบ @ AndrewKennan ของฉันที่ฉันใช้เมื่อไม่นานมานี้สำหรับประเภทที่ได้รับขณะใช้งานจริง:

if (serviceType.IsInstanceOfType(service))
{
    // 'service' does implement the 'serviceType' type
}

7

นี้โพสต์เป็นคำตอบที่ดี

public interface IMyInterface {}

public class MyType : IMyInterface {}

นี่คือตัวอย่างง่ายๆ:

typeof(IMyInterface).IsAssignableFrom(typeof(MyType))

หรือ

typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))

3

นอกเหนือจากการทดสอบโดยใช้โอเปอเรเตอร์ "is" แล้วคุณสามารถตกแต่งวิธีการของคุณเพื่อให้แน่ใจว่าตัวแปรที่ส่งผ่านไปยังอินเทอร์เฟซที่เฉพาะเจาะจงเช่น:

public static void BubbleSort<T>(ref IList<T> unsorted_list) where T : IComparable
{
     //Some bubbly sorting
}

ฉันไม่แน่ใจว่าเวอร์ชั่นของ. Net นี้ได้รับการติดตั้งใช้งานหรือไม่ในเวอร์ชันของคุณ


2
.net 2.0 เพิ่ม generics
Robert C. Barth

นี่เป็นเพียง การตรวจสอบเวลาคอมไพล์ในกระทู้นี้เท่านั้นขอบคุณ
ดัสตินมาโลน

2

สิ่งที่ได้ผลสำหรับฉันคือ:

Assert.IsNotNull(typeof (YourClass).GetInterfaces().SingleOrDefault(i => i == typeof (ISomeInterface)));


1

เมื่อเร็ว ๆ นี้ฉันลองใช้คำตอบของ Andrew Kennan และมันก็ไม่ได้ผลสำหรับฉันด้วยเหตุผลบางอย่าง ฉันใช้สิ่งนี้แทนและใช้งานได้ (หมายเหตุ: อาจจำเป็นต้องเขียนเนมสเปซ)

if (typeof(someObject).GetInterface("MyNamespace.IMyInterface") != null)

2
หากคุณไปเส้นทางนี้ฉันไม่ใช่แฟนตัวยงของเวทย์มนตร์ดังนั้นอย่างน้อยฉันก็ควรเปลี่ยนให้เป็น typeof (IMyInterface). ชื่อแทน "MyNamespace.IMyInterface" ช่วยในการตั้งชื่อหลักฐานการปรับโครงสร้างใหม่เป็นโบนัส
greyalien007

0

ฉันใช้

Assert.IsTrue(myObject is ImyInterface);

สำหรับการทดสอบในการทดสอบหน่วยของฉันซึ่งการทดสอบที่ myObject เป็นวัตถุที่ใช้อินเตอร์เฟซของฉัน ImyInterface


-1

ฉันมีสถานการณ์ที่ฉันส่งตัวแปรไปยังเมธอดและไม่แน่ใจว่ามันจะเป็นอินเทอร์เฟซหรือวัตถุ

เป้าหมายคือ:

  1. ถ้า item เป็นอินเตอร์เฟสให้สร้างอินสแตนซ์ของออบเจกต์ตามอินเตอร์เฟสนั้นด้วยอินเตอร์เฟสที่เป็นพารามิเตอร์ในการเรียก constructor
  2. หากรายการนั้นเป็นวัตถุให้ส่งคืนค่า null เนื่องจาก constuctor สำหรับการโทรของฉันคาดว่าจะมีส่วนต่อประสานและฉันไม่ต้องการให้โค้ดเก็บรถถัง

ฉันทำสิ่งนี้สำเร็จด้วยสิ่งต่อไปนี้:

    if(!typeof(T).IsClass)
    {
       // If your constructor needs arguments...
       object[] args = new object[] { my_constructor_param };
       return (T)Activator.CreateInstance(typeof(T), args, null);
    }
    else
       return default(T);

-12

สิ่งนี้น่าจะใช้ได้:

MyInstace.GetType().GetInterfaces();

แต่ก็ดีเช่นกัน:

if (obj is IMyInterface)

หรือแม้กระทั่ง (ไม่สง่างามมาก):

if (obj.GetType() == typeof(IMyInterface))

9
การตรวจสอบความเท่าเทียมกันในการพิมพ์ (IMyInterface) จะล้มเหลวเสมอ downvoted
Jay Bazuzi

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