Как определить, реализует ли тип интерфейса с отражением С#

Отражает ли отражение в C# способ определить, поддерживает ли какой-то определенный тип System.Type некоторый интерфейс?

public interface IMyInterface {}

public class MyType : IMyInterface {}

// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);

Ответ 1

У вас есть несколько вариантов с моей головы

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

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

Для общего интерфейса это немного отличается.

typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))

Ответ 2

Используйте Type.IsAssignableFrom:

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

Ответ 3

typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

или

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

Ответ 4

public static bool ImplementsInterface(this Type type, Type ifaceType) 
{
    Type[] intf = type.GetInterfaces();
    for(int i = 0; i < intf.Length; i++) 
    {
        if(intf[ i ] == ifaceType) 
        {
            return true;
        }
    }
    return false;
}

Я думаю, что это правильный выпуск по трем причинам:

  1. Он использует GetInterfaces, а не IsAssignableFrom, это быстрее, так как IsAssignableFrom в конце концов после нескольких проверок вызывает GetInterfaces.
  2. Он перебирает локальный массив, поэтому будет без ограничений.
  3. Он использует оператор ==, который определен для Тип, так что, вероятно, безопаснее, чем метод Equals (что содержит позвони, со временем буду пользоваться).

Ответ 5

Я только что сделал:

public static bool Implements<I>(this Type source) where I : class
{
  return typeof(I).IsAssignableFrom(source);
}

Мне хотелось бы сказать where I : interface, но interface не является опцией ограничения общих параметров. class находится как можно ближе.

Использование:

if(MyType.Implements<IInitializable>())
  MyCollection.Initialize();

Я только что сказал Implements, потому что это более интуитивно понятно. Я всегда получаю IsAssignableFrom flip-flopped.

Ответ 6

Как кто-то еще уже упоминал: Бенджамин 10 апреля '13 в 22:21

Конечно, было легко не обращать внимания и получать аргументы для IsAssignableFrom в обратном направлении. Я пойду с GetInterfaces сейчас: p -

Что ж, другой путь - просто создать короткий метод расширения, который в некоторой степени соответствует "наиболее привычному" образу мышления (и согласился, что это очень маленький личный выбор, чтобы сделать его немного "более естественным" на основе одного предпочтения). ):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }
}

И почему бы не пойти немного более обобщенно (ну, не уверен, действительно ли это так интересно, ну, я полагаю, я просто пропускаю очередную щепотку "синтаксического" сахара):

public static class TypeExtensions
{
    public static bool IsAssignableTo(this Type type, Type assignableType)
    {
        return assignableType.IsAssignableFrom(type);
    }

    public static bool IsAssignableTo<TAssignable>(this Type type)
    {
        return IsAssignableTo(type, typeof(TAssignable));
    }
}

Я думаю, что это может быть гораздо более естественным, но, опять же, вопрос личного мнения:

var isTrue = michelleType.IsAssignableTo<IMaBelle>();

Ответ 7

Изменение ответа Джеффа для оптимальной производительности (благодаря тесту производительности Пьером Арно):

var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;

Чтобы найти все типы, реализующие интерфейс в заданном Assembly:

var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
                          .Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);

Ответ 8

IsAssignableFrom теперь перемещен в TypeInfo:

typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());

Ответ 9

Правильный ответ

typeof(MyType).GetInterface(nameof(IMyInterface)) != null;

Однако

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

может возвращать неверный результат, так как следующий код показывает строку и IConvertible:

    static void TestIConvertible()
    {
        string test = "test";
        Type stringType = typeof(string); // or test.GetType();

        bool isConvertibleDirect = test is IConvertible;
        bool isConvertibleTypeAssignable = stringType.IsAssignableFrom(typeof(IConvertible));
        bool isConvertibleHasInterface = stringType.GetInterface(nameof(IConvertible)) != null;

        Console.WriteLine($"isConvertibleDirect: {isConvertibleDirect}");
        Console.WriteLine($"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}");
        Console.WriteLine($"isConvertibleHasInterface: {isConvertibleHasInterface}");
    }

Результаты:

 isConvertibleDirect: True
 isConvertibleTypeAssignable: False
 isConvertibleHasInterface: True

Ответ 10

Что насчет

typeof(IWhatever).GetTypeInfo().IsInterface

Ответ 11

Обратите внимание, что если у вас есть универсальный интерфейс IMyInterface<T> это всегда будет возвращать false:

  typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */

Это тоже не работает:

  typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>))  /* ALWAYS FALSE */

Однако, если MyType реализует IMyInterface<MyType> это работает и возвращает true:

  typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))

Однако вы, вероятно, не будете знать параметр типа T во время выполнения. Несколько хакерское решение:

  typeof(MyType).GetInterfaces()
                .Any(x=>x.Name == typeof(IMyInterface<>).Name)

Решение Джеффа немного менее хакерское:

  typeof(MyType).GetInterfaces()
         .Any(i => i.IsGenericType 
             && i.GetGenericTypeDefinition() == typeof(IMyInterface<>));

Вот метод расширения Type который работает для любого случая:

public static class TypeExtensions
{
    public static bool IsImplementing(this Type type, Type someInterface)
    {
        return type.GetInterfaces()
             .Any(i => i == someInterface 
                 || i.IsGenericType 
                    && i.GetGenericTypeDefinition() == someInterface);
    }
}

(Обратите внимание, что выше используется linq, который, вероятно, медленнее, чем цикл.)

Затем вы можете сделать:

   typeof(MyType).IsImplementing(IMyInterface<>)

Ответ 12

Car.cs - Интерфейс

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  

namespace Reflection  
{  
    interface ICar  
    {  
        bool IsMoving();  
    }  
}  
Car.cs - Class
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  

namespace Reflection  
{  
    internal class Car  
    {  
        //public variables  
        public string Color;  

        //private variables  
        //String licensePlate; // e.g. "Californi 111 222"  
        //double maxSpeed;     // in kilometers per hour  
        //int startMiles; // Stating odometer reading   
        //int endMiles; // Ending odometer reading   
        //double gallons; // Gallons of gas used between the readings   

        //private vaiables  
        private int _speed;  

        //Speed - read-only property to return the speed  
        public int Speed  
        {  
            get { return _speed; }  
        }  

        //Accelerate - add mph to the speed  
        public void Accelerate(int accelerateBy)  
        {  
            //Adjust the speed  
            _speed += accelerateBy;  
        }  

        //IsMoving - is the car moving?  
        public bool IsMoving()  
        {  
            //Is the car speed zero?  
            if (Speed == 0)  
            {  
                return false;  
            }  
            else  
            {  
                return true;  
            }  
        }  

        //Constructor  
        public Car()  
        {  
            //Set the default values  
            Color = "White";  
            _speed = 0;  
        }  

        //Over loaded constructor  
        public Car(string color, int speed)  
        {  
            Color = color;  
            _speed = speed;  
        }  
        //methods  
        public double calculateMPG(int startMiles, int endMiles, double gallons)  
        {  
            return (endMiles - startMiles) / gallons;  
        }    
    }  
}  

SportsCar.cs - Класс

 using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  

    namespace Reflection  
    {  
        internal class SportsCar : Car  
        {  
            //Constructor  
            public SportsCar()  
            {  
                //Change the default values  
                Color = "Green";  
            }  
        }  
    }  

Использование оператора typeof() С#

Последний способ получения информации о типе - использование оператора typeof С#. Этот оператор принимает имя типа в качестве параметра.

TypeofDemo.cs

using System;  
namespace Reflection  
{  
    class TypeofDemo  
    {  
        static void Main(string[] args)  
        {  
            // Get the Type using typeof.  
            Type t = typeof(Car);  
            Console.WriteLine(t.FullName);  
            Console.ReadLine();  
        }  
    }  
}  

Ответ 13

Если у вас есть тип или экземпляр, вы можете легко проверить, поддерживают ли они определенный интерфейс.

Чтобы проверить, реализует ли объект определенный интерфейс:

if(myObject is IMyInterface) {
  // object myObject implements IMyInterface
}

Чтобы проверить, реализует ли тип определенный интерфейс:

if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
  // type MyType implements IMyInterface
}

Если вы получили универсальный объект и хотите выполнить приведение, а также проверить, реализован ли интерфейс, к которому вы приведете, код:

 var myCastedObject = myObject as IMyInterface;

    if(myCastedObject != null) {
      // object myObject implements IMyInterface
    }

Ответ 14

как насчет

if(MyType as IMyInterface != null)

?