Определите, реализует ли класс очень специфический интерфейс

В этой теме много вопросов, но у меня есть слегка измененная версия.

У нас есть следующий код:

interface IFoo { }
interface IBar : IFoo { }
class Foo : IFoo { }
class Bar : IBar { }

bool Implements_IFoo(Type type) { /* ??? */ }

Теперь, поворот истории: метод Implements_IFoo должен возвращать true только тогда, когда Type реализует только IFoo, а не какие-либо интерфейсы, полученные из IFoo. Для иллюстрации здесь приведены некоторые примеры этого метода:

Implements_IFoo(typeof(Foo)); // Should return true

Implements_IFoo(typeof(Bar)); // Should return false as Bar type 
                              // implements an interface derived from IFoo

Обратите внимание, что могут быть многочисленные интерфейсы, полученные из IFoo, и вы не обязательно знаете об их существовании.

Очевидным методом является поиск всех интерфейсов, полученных из IFoo через отражение, а затем просто проверка типа (Bar).GetInterfaces() - это любой из них. Но мне было интересно, может ли кто-нибудь придумать более элегантное решение.

PS Вопрос возникает из некоторого кода, который я нашел, который использует эту проверку для классов (if(obj.GetType() == typeof(BaseClass)) { ... }). Мы заменяем классы интерфейсами теперь, что конкретный код. Кроме того, на всякий случай - я выполняю эту проверку как булевский флаг, поэтому этот вопрос является чисто гипотетическим.

Ответ 1

У меня была попытка, потому что это звучало как забава, и это работает для вашего примера:

bool ImplementsIFooDirectly(Type t) {
    if (t.BaseType != null && ImplementsIFooDirectly(t.BaseType)) { 
        return false; 
    }
    foreach (var intf in t.GetInterfaces()) {
        if (ImplementsIFooDirectly(intf)) { 
            return false;
        }
    }
    return t.GetInterfaces().Any(i => i == typeof(IFoo));
}

:

ImplementsIFooDirectly(typeof(IFoo)); // false
ImplementsIFooDirectly(typeof(Bar)); // false
ImplementsIFooDirectly(typeof(Foo)); // true
ImplementsIFooDirectly(typeof(IBar)); // true

Он не ищет все интерфейсы, полученные из IFoo, он просто перемещается по цепочке реализации наследования/интерфейса и видит, присутствует ли IFoo на любом уровне, отличном от точного уровня типа.

Он также определяет, наследуется ли интерфейс через базовый тип. Не уверен, что это то, что вы хотите.

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

Ответ 2

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

С# - использование ключевых слов

По существу, вы можете использовать ключевое слово 'is', чтобы определить, является ли объект обитаемым в классе типа частью его класса наследования.

class Director  : Owner { }
class Developer : Employee { }
..
var dave = new Developer();
var steve = new Director();
var isEmployee = dave is Employee; // true
var isAlsoEmploye = steve is Employee; // false

В соответствии с вашей примерной функцией:

bool Implements_Type(object instance, Type type) { 
return instance is type;
}

Ответ 3

static bool Implements_IFoo(Type type)
{
  if (typeof(IFoo).IsAssignableFrom(type.BaseType))
    return false;

  var barInterfaces = type.GetInterfaces()
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface))
    .ToArray();

  return barInterfaces.Length > 0 
     && barInterfaces.Length == barInterfaces.Count(iface => iface == typeof(IFoo));
}
static bool Implements_IFoo_Optimized(Type type)
{
  if (typeof(IFoo).IsAssignableFrom(type.BaseType))
    return false;

  return type.GetInterfaces()
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface))
    .Count() == 1;
}

Ответ 4

Это должно сделать трюк:

 public bool ImplementsIFooOnly(Type type)
 {
     return !type.GetInterfaces().Any(t => 
              { 
                   return t is IFoo && !t.Equals(typeof(IFoo)); 
              });
 }

Есть, вероятно, более эффективные способы.

Ответ 5

Вы пытались использовать ключевое слово is?

Кстати, если у вас есть логический случай, когда некоторый класс должен быть типа некоторого базового класса, но не одного из наследников, он, вероятно, ошибочный дизайн OO, который может нарушить Принцип подстановки Лискова.

Ответ 6

Класс Type имеет метод GetInterface, который вы можете использовать.

    bool Implements_IFoo(Type t)
    {
        return t.GetInterface(typeof(IFoo).Name) != null;
    }