假设以下假设的继承层次结构:
public interface IA { int ID { get; set; } } public interface IB : IA { string Name { get; set; } }
使用反射并进行以下调用:
typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance)
只会产生接口的属性IB
,即" Name
".
如果我们要对以下代码进行类似的测试,
public abstract class A { public int ID { get; set; } } public class B : A { public string Name { get; set; } }
该调用typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance)
将返回PropertyInfo
" ID
"和" Name
" 的对象数组.
有没有一种简单的方法来查找接口的继承层次结构中的所有属性,如第一个示例中所示?
我已经将@Marc Gravel的示例代码调整为有用的扩展方法,封装了类和接口.它还首先添加了接口属性,我认为这是预期的行为.
public static PropertyInfo[] GetPublicProperties(this Type type) { if (type.IsInterface) { var propertyInfos = new List(); var considered = new List (); var queue = new Queue (); considered.Add(type); queue.Enqueue(type); while (queue.Count > 0) { var subType = queue.Dequeue(); foreach (var subInterface in subType.GetInterfaces()) { if (considered.Contains(subInterface)) continue; considered.Add(subInterface); queue.Enqueue(subInterface); } var typeProperties = subType.GetProperties( BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); var newPropertyInfos = typeProperties .Where(x => !propertyInfos.Contains(x)); propertyInfos.InsertRange(0, newPropertyInfos); } return propertyInfos.ToArray(); } return type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance); }
Type.GetInterfaces
返回展平的层次结构,因此不需要递归下降.
使用LINQ可以更简洁地编写整个方法:
public static IEnumerableGetPublicProperties(this Type type) { if (!type.IsInterface) return type.GetProperties(); return (new Type[] { type }) .Concat(type.GetInterfaces()) .SelectMany(i => i.GetProperties()); }
接口层次结构是一种痛苦 - 它们并不真正"继承",因为你可以拥有多个"父母"(因为想要更好的术语).
"扁平化"(再次,不是正确的术语)层次结构可能涉及检查接口实现的所有接口并从那里开始工作......
interface ILow { void Low();} interface IFoo : ILow { void Foo();} interface IBar { void Bar();} interface ITest : IFoo, IBar { void Test();} static class Program { static void Main() { Listconsidered = new List (); Queue queue = new Queue (); considered.Add(typeof(ITest)); queue.Enqueue(typeof(ITest)); while (queue.Count > 0) { Type type = queue.Dequeue(); Console.WriteLine("Considering " + type.Name); foreach (Type tmp in type.GetInterfaces()) { if (!considered.Contains(tmp)) { considered.Add(tmp); queue.Enqueue(tmp); } } foreach (var member in type.GetMembers()) { Console.WriteLine(member.Name); } } } }