Как проверить, реализует ли один тип .NET определенный интерфейс .NET абстрактно? - PullRequest
9 голосов
/ 28 октября 2009

У меня есть тип и интерфейс, и мне нужно убедиться, что тип реализует интерфейс абстрактно.

Я решил написать код грубой силы, используя Reflection, и это довольно уродливо.

Мне интересно, есть ли лучший способ, чем реализация грубой силы, которую я делаю сейчас.

Есть идеи?

Спасибо.

EDIT

Еще не проверили реализацию, но черновой код грубой силы выглядит так:

  public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface)
  {
    if (!someInterface.IsAssignableFrom(someType))
    {
      return false;
    }

    if (!someType.IsAbstract)
    {
      return false;
    }

    var m_interfaceMemberNames = someInterface.GetMembers().Select(m => m.Name).ToList();
    // Make sure every interface member implementation is abstract.
    foreach (var typeMember in someType.FindMembers(MemberTypes.Event | MemberTypes.Property | MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, null, null))
    {
      if (m_interfaceMemberNames.Contains(typeMember.Name))
      {
        MethodInfo method;
        // Make sure the ancestor member is abstract.
        switch (typeMember.MemberType)
        {
        case MemberTypes.Event:
          if (!IsAbstractImplementation(((EventInfo)typeMember).GetAddMethod()))
          {
            return false;
          }
          method = ((EventInfo)typeMember).GetRemoveMethod();
          break;
        case MemberTypes.Property:
          method = ((PropertyInfo)typeMember).GetGetMethod();
        default:
          method = (MethodInfo)typeMember;
          break;
        }
        if (!IsAbstractImplementation(method))
        {
          return false;
        }
      }
    }
    return true;
  }

  public static bool IsAbstractImplementation(MethodInfo methodInfo)
  {
    const MethodAttributes expectedAttributes =
      MethodAttributes.Abstract |
      MethodAttributes.Public |
      MethodAttributes.NewSlot |
      MethodAttributes.Virtual;

    return (methodInfo.Attributes & expectedAttributes) == expectedAttributes;
  }

Не компилируя его, я уже вижу проблему со свойствами, заключающуюся в том, что код должен проверять, определяет ли интерфейс геттер и / или сеттер, и проверять правильные методы, вместо того, чтобы слепо предполагать геттер. В любом случае, как видите, код довольно скучный. Мне интересно, есть ли лучший способ ...

РЕДАКТИРОВАТЬ 2

  • Хочу подчеркнуть, что это всего лишь черновая реализация, она работает для простых случаев и не работает для более сложных, например, когда есть перегрузки методов или переименования методов (я не знаю VB, поэтому я не сделал даже думаю, что это возможно). Но это подчеркивает мою точку зрения, что для того, чтобы сделать это правильно, требуется много работы.
  • Зачем мне такая вещь? Нам нужно создавать типы динамически, используя Reflection.Emit на основе определенных динамически полученных метаданных. Сгенерированный динамический тип реализует определенный интерфейс, скажем, IDynamicObject, и может происходить от некоторого предкового типа. Этот тип предка статически компилируется. До недавнего времени типу предка не разрешалось реализовывать интерфейс IDynamicObject. Учитывая экземпляр динамического типа, нужно было явно привести его к IDynamicObject, чтобы получить доступ к его методам (помните, что сгенерированный динамический тип действительно реализует интерфейс). Я хотел бы устранить эти явные приведения. Единственный способ сделать это - позволить типу предка реализовать интерфейс IDynamicObject. Однако реализация должна быть полностью абстрактной, что подтверждается кодом создания динамического типа. Вуаля.

Ответы [ 4 ]

27 голосов
/ 28 октября 2009

Вы можете определить, реализует ли тип конкретный интерфейс, используя Type.IsAssignableFrom :

typeof(MyInterface).IsAssignableFrom(abstractType);

Редактировать: после того, как пояснение было добавлено к ответу - чтобы определить, являются ли все реализации интерфейса абстрактными для данного класса, вы можете сделать это намного проще, получив InterfaceMap для рассматриваемого типа:

bool IsAbstractOfInterface(Type classType, Type interfaceType)
{
    var map = classType.GetInterfaceMap(interfaceType);
    foreach (var info in map.TargetMethods)
    {
        if (!info.IsAbstract)
        {
            return false;
        }
    }
    return true;
}

Или, может быть, общий метод расширения ...

public static bool IsAbstractOf<TInterface>(this Type type)
{
    var map = type.GetInterfaceMap(typeof(TInterface));
    foreach (var info in map.TargetMethods)
    {
        if (!info.IsAbstract)
        {
            return false;
        }
    }
    return true;
}
1 голос
/ 28 октября 2009
public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface)
{
    return someType.IsAbstract && someInterface.IsAssignableFrom(someType);
}
1 голос
/ 28 октября 2009

Ответ Рекса М в целом правильный, но если ваш тип является параметром типа, вы также можете сделать:

class Foo<T> where T : IWhatever {
    // Do your thing, secure in the knowledge that T implements IWhatever
}
0 голосов
/ 28 октября 2009

Вы не можете использовать имена участников. Потому что нет никаких оснований предполагать, что имя члена говорит вам что-либо об элементе интерфейса, который он реализует. Reflection предоставляет вам средства, чтобы увидеть, какой метод реализует какой из интерфейса, хотя.

Вот фрагмент кода, который возвращает все методы данного типа, которые реализованы только абстрактно.

static IEnumerable<MethodInfo> GetAbstractImplementations(this Type implementingType, Type interfaceType)
{
    if(!interfaceType.IsInterface)
        throw new ArgumentException(interfaceType.FullName + " is not an interface.");
    if(implementingType.IsInterface)
        throw new ArgumentException(interfaceType.FullName + " is an interface.");

    if(!interfaceType.IsAssignableFrom(implementingType))
        throw new ArgumentException(implementingType.FullName + " does not implement " + interfaceType.FullName + ".");

    var mapping = implementingType.GetInterfaceMap(interfaceType);
    return from m  in mapping.TargetMethods 
           where m.IsAbstract
           select m;
}

public static bool IsAbstractInterfaceImplementationOf(this Type implementingType, Type interfaceType)
{
    return implementingType.GetAbstractImplementations(interfaceType).Any();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...