Как определить, реализует ли тип интерфейса с отражением С#
Отражает ли отражение в C#
способ определить, поддерживает ли какой-то определенный тип System.Type
некоторый интерфейс?
public interface IMyInterface {}
public class MyType : IMyInterface {}
// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
Ответы
Ответ 1
У вас есть несколько вариантов с моей головы
-
typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
-
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;
}
Я думаю, что это правильный выпуск по трем причинам:
- Он использует GetInterfaces, а не IsAssignableFrom, это быстрее, так как
IsAssignableFrom в конце концов после нескольких проверок вызывает
GetInterfaces.
- Он перебирает локальный массив, поэтому будет
без ограничений.
- Он использует оператор ==, который определен для
Тип, так что, вероятно, безопаснее, чем метод 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)
?