Перевірте, чи об'єкт реалізує інтерфейс


355

Який найпростіший спосіб тестування, якщо об’єкт реалізує заданий інтерфейс у C #? (Відповідь на це питання на Java )

Відповіді:


569
if (object is IBlah)

або

IBlah myTest = originalObject as IBlah

if (myTest != null)

85
+1 Другий краще, тому що вам, ймовірно, доведеться згодом відкидати перший, таким чином, ви отримаєте два ролі ("є", а потім явний склад). З другим підходом ви виступаєте лише один раз.
Ендрю Заєць

51
@Andrew: +1; Знову час для посилання на класичну публікацію блогу подвійного кастингу AntiPattern від Julian M Bucknall .
Jeroen Wiert Pluimers

1
Оптимізація, ймовірно, не зробить вас двічі в першому випадку?
BuZz

1
@Joreen, це посилання не вистачає однієї точки, якщо ви працюєте зі структурою, яку ви не можете використовувати "як", тому що вона не може утримувати нуль, і це те, що намагається повернути "як", у такому випадку вам доведеться пройти нульовий клас на зразок int ?, хоча це не проблема, якщо ваш єдиний працює на рівні інтерфейсу, оскільки вони завжди є
типовими

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.
Ендрю Кеннан

Я використовую це для перевірки типу в плагіновій системі. Його можна використовувати в ситуаціях, коли екземпляр об'єкта ще не існує. Але я використовую і цей стиль, і Роберта залежно від того, що я роблю, тому я проголосував обома способами.
Джеймс

Це більш старий коментар, але щоб відповісти на запитання @ Steenreem, використовуйте typeof(IList).IsAssignableFrom(someType)без цього <>.
салюс

Цей метод працює навіть з операторами перетворення, і якщо задіяні TypeConverters
Харальд Коппулз

22

Наприклад:

if (obj is IMyInterface) {}

Для класу:

Перевірте, чи typeof(MyClass).GetInterfaces()містить інтерфейс.


1
if (Array.IndexOf (typeof (MyClass) .GetInterfaces (), typeof (IMyInterface))! = -1) {...}
Константин

2
або: if (typeof (MyClass) .GetInterfaces (). Містить (typeof (IMyInterface))) {...}
Lance Fisher


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

Окрім тестування за допомогою оператора "є", ви можете прикрасити свої методи, щоб переконатися, що змінні, передані йому, реалізують певний інтерфейс, наприклад:

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

Я не впевнений, у якій версії .Net це було реалізовано, тому воно може не працювати у вашій версії.


2
.net 2.0 додав дженерики.
Роберт К. Барт

Це єдина перевірка часу компіляції в цій темі, дякую.
Дастін Малоун


1

Нещодавно я спробував використати відповідь Ендрю Кеннана, і мені це чомусь не вийшло. Я використовував це замість цього, і це спрацювало (зверніть увагу: можливо, буде потрібно записувати простір імен).

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

2
Якщо ви закінчите цей шлях, я не є фанатом магічних рядків, тому я як мінімум зміню це на типof (IMyInterface) .Name замість "MyNamespace.IMyInterface". Допомагає зробити його доказом рефакторингу як бонусом.
greyalien007

0

я використав

Assert.IsTrue(myObject is ImyInterface);

для тесту в моєму модульному тесті, який перевіряє, що myObject є об'єктом, який реалізував мій інтерфейс ImyInterface.


-1

У мене була ситуація, коли я передавав змінну методу і не був впевнений, чи буде це інтерфейс чи об’єкт.

Цілями були:

  1. Якщо елемент є інтерфейсом, інстанціюйте об'єкт на основі цього інтерфейсу, при цьому інтерфейс є параметром у виклику конструктора.
  2. Якщо об'єкт є об'єктом, поверніть нуль, оскільки кондуктор для моїх дзвінків очікує інтерфейс, і я не хотів, щоб код заряджався.

Я досяг цього:

    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
Перевірка рівності типу typeof (IMyInterface) завжди буде невдалою. Захищений.
Джей Базузі

Правильно. Жодних примірників інтерфейсу немає.
Раухоц
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.