Найти только не наследуемые интерфейсы?
Я пытаюсь выполнить запрос на интерфейсах класса через отражение, однако метод 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);