Найти только не наследуемые интерфейсы?

Я пытаюсь выполнить запрос на интерфейсах класса через отражение, однако метод Type.GetInterfaces() также возвращает все наследуемые интерфейсы.

и т.д.

public class Test : ITest { }

public interface ITest : ITesting { }

Код

typeof(Test).GetInterfaces();

Вернет a Type[], содержащий как ITest, так и ITesting, где, поскольку я хочу только ITest, существует ли другой метод, который позволяет указать наследование?

Спасибо, Алекс.

EDIT: Из ответов ниже я собрал это,

Type t;
t.GetInterfaces().Where(i => !t.GetInterfaces().Any(i2 => i2.GetInterfaces().Contains(i)));

Выше, похоже, работает, поправьте меня в комментариях, если он не

Ответ 1

Вы можете попробовать что-то вроде этого:

Type[] allInterfaces = typeof(Test).GetInterfaces();
var exceptInheritedInterfaces = allInterfaces.Except(
  allInterfaces.SelectMany(t => t.GetInterfaces())
);

Итак, если у вас есть что-то вроде этого:

public interface A : B
{
}

public interface B : C
{
}

public interface C
{
}

public interface D
{
}

public class MyType : A, D
{
}

Код вернет A и D

Ответ 2

Крупный специалист в .NET может исправить меня, если я ошибаюсь, но я не считаю, что это возможно. Внутри я полагаю, что .NET framework фактически не поддерживает эту иерархию, и она сглаживается, когда она скомпилирована в код IL.

Например, код С#:

class Program : I2
{
    static void Main(string[] args)
    {
    }
}

interface I1
{
}

interface I2 : I1
{
}

После того, как он встроен в код IL, это:

.class private auto ansi beforefieldinit ReflectionTest.Program
       extends [mscorlib]System.Object
       implements ReflectionTest.I2,
                  ReflectionTest.I1
{
    ...

Что точно такое же, как class Program : I1, I2


Однако, также в IL:

.class interface private abstract auto ansi ReflectionTest.I2
       implements ReflectionTest.I1
{
    ...

Это означает, что вы можете написать некоторую логику, чтобы получить (из моего примера) I1 и I2 из класса Program, затем запросить каждый из этих интерфейсов, чтобы увидеть, реализуют ли они один из других... Другими словами, поскольку typeof(I2).GetInterfaces() содержит I1, вы можете сделать вывод, что, поскольку typeof(Program).GetInterfaces() возвращает I1 и I2, тогда Program может не наследовать непосредственно I1 в коде.

Я подчеркиваю, возможно, не потому, что это также действительный код С# и будет делать тот же IL-код (а также те же результаты отражения):

class Program : I1, I2
{
    static void Main(string[] args)
    {
    }
}

interface I1
{
}

interface I2 : I1
{
}

Теперь Program прямо и косвенно наследует I1...

Ответ 3

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

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

Этот подход немного чрезмерно агрессивный, потому что если вы объявляете IFoo и IBar для непосредственного класса AND IFoo требуется IBar, он будет удален (но действительно, что это такое больше, чем упражнение в любопытстве? Практическая полезность этого мне непонятна...)

Этот код уродливый, но я просто выбросил его в новую/голую установку MonoDevelop...

public static void Main (string[] args)
{
    var nonInheritedInterfaces = typeof(Test).GetImmediateInterfaces();
    foreach(var iface in nonInheritedInterfaces)
    {
        Console.WriteLine(iface);
    }
    Console.Read();
}

class Test : ITest { }

interface ITest : ITestParent { }

interface ITestParent { }

public static class TypeExtensions
{
    public static Type[] GetImmediateInterfaces(this Type type)
    {
        var allInterfaces = type.GetInterfaces();
        var nonInheritedInterfaces = new HashSet<Type>(allInterfaces);
        foreach(var iface in allInterfaces)
        {
            RemoveInheritedInterfaces(iface, nonInheritedInterfaces);
        }
        return nonInheritedInterfaces.ToArray();
    }

    private static void RemoveInheritedInterfaces(Type iface, HashSet<Type> ifaces)
    {
        foreach(var inheritedIface in iface.GetInterfaces())
        {
            ifaces.Remove(inheritedIface);
            RemoveInheritedInterfaces(inheritedIface, ifaces);
        }
    }
}

private static void RemoveInheritedInterfaces(Type iface, Dictionary<Type, Type> interfaces)
{
    foreach(var inheritedInterface in iface.GetInterfaces())
    {
        interfaces.Remove(inheritedInterface);
        RemoveInheritedInterfaces(inheritedInterface, interfaces);
    }
}

Ответ 4

В моей предыдущей попытке я не смог добиться успеха.

 Type[] types = typeof(Test).GetInterfaces();

 var directTypes = types.Except
                    (types.SelectMany(t => t.GetInterfaces()));

  foreach (var t in directTypes)
  {

  }

Надеюсь, это поможет кому-то.

Ответ 5

Похоже, нет никакого тривиального вызова метода для этого, поскольку в основном при компиляции выполняются следующие значения:

MyClass : IEnumerable<bool>

и

MyClass : IEnumerable<bool>,IEnumerable

Вы можете опросить каждый интерфейс и запросить его интерфейсы. И посмотрите, находятся ли они в списке формеров. Необычно, для классов GetInterfaces является рекурсивным. То есть он получает все уровни наследования. Для интерфейсов он не рекурсивный. Например: IList возвращает IList и ICollection, но не упоминает о IEnumerable, который реализуется ICollection.

Однако вы, скорее всего, интересуетесь методами, реализованными уникально каждым интерфейсом и их привязкой, и в этом случае вы можете использовать метод GetInterfaceMap(Type).

Ответ 6

попробуйте следующее:

    Type t = typeof(Test);
    int max = 0;
    Type result = null;
    foreach (Type type in t.GetInterfaces())
    {
        int len = type.GetInterfaces().Length;
        if (len > max)
        {
            max = len;
            result = type;
        }
    }
    if (result != null)
        Console.WriteLine(result.FullName);

Ответ 7

    Type t = typeof(Test);
    int max = 0;
    List<Type> results = new List<Type>();
    foreach (Type type in t.GetInterfaces())
    {
        int len = type.GetInterfaces().Length;
        if (len > max)
        {
            max = len;
            results.Add(type);
        }
    }
    if (results.Count > 0)
        foreach (Type type in results)
            Console.WriteLine(type.FullName);