C# GetProperties() 返回接口继承层次结构的所有属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/358835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:25:56  来源:igfitidea点击:

GetProperties() to return all properties for an interface inheritance hierarchy

c#.netreflection

提问by sduplooy

Assuming the following hypothetical inheritance hierarchy:

假设以下假设的继承层次结构:

public interface IA
{
  int ID { get; set; }
}

public interface IB : IA
{
  string Name { get; set; }
}

Using reflection and making the following call:

使用反射并进行以下调用:

typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance) 

will only yield the properties of interface IB, which is "Name".

只会产生 interface 的属性IB,即“ Name”。

If we were to do a similar test on the following code,

如果我们对下面的代码做一个类似的测试,

public abstract class A
{
  public int ID { get; set; }
}

public class B : A
{
  public string Name { get; set; }
}

the call typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance)will return an array of PropertyInfoobjects for "ID" and "Name".

调用typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance)将返回PropertyInfoID”和“ Name”的对象数组。

Is there an easy way to find all the properties in the inheritance hierarchy for interfaces as in the first example?

是否有一种简单的方法可以像第一个示例中那样在接口的继承层次结构中查找所有属性?

采纳答案by mythz

I've tweaked @Marc Gravel's example code into a useful extension method encapsulates both classes and interfaces. It also add's the interface properties first which I believe is the expected behaviour.

我已经将@Marc Gravel 的示例代码调整为一个有用的扩展方法,封装了类和接口。它还首先添加了接口属性,我认为这是预期的行为。

public static PropertyInfo[] GetPublicProperties(this Type type)
{
    if (type.IsInterface)
    {
        var propertyInfos = new List<PropertyInfo>();

        var considered = new List<Type>();
        var queue = new Queue<Type>();
        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);
}

回答by Marc Gravell

Interface hierarchies are a pain - they don't really "inherit" as such, since you can have multiple "parents" (for want of a better term).

接口层次结构是一种痛苦——它们并没有真正“继承”,因为你可以有多个“父级”(因为想要一个更好的术语)。

"Flattening" (again, not quite the right term) the hierarchy might involve checking for all the interfaces that the interface implements and working from there...

“扁平化”(同样,不是完全正确的术语)层次结构可能涉及检查接口实现的所有接口并从那里开始工作......

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()
    {
        List<Type> considered = new List<Type>();
        Queue<Type> queue = new Queue<Type>();
        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);
            }
        }
    }
}

回答by Wolf5

Exactly the same problem has a workaround described here.

完全相同的问题有一个解决方法描述here

FlattenHierarchy doesnt work btw. (only on static vars. says so in intellisense)

顺便说一句,FlattenHierarchy 不起作用。(仅在静态变量上。在智能感知中如此说)

Workaround. Beware of duplicates.

解决方法。小心重复。

PropertyInfo[] pis = typeof(IB).GetProperties(BindingFlags.Public | BindingFlags.Instance);
Type[] tt = typeof(IB).GetInterfaces();
PropertyInfo[] pis2 = tt[0].GetProperties(BindingFlags.Public | BindingFlags.Instance);

回答by Derek Strickland

this worked nicely and tersely for me in a custom MVC model binder. Should be able to extrapolate to any reflection scenario though. Still kind of stinks that it's too pass

在自定义 MVC 模型绑定器中,这对我来说非常有效且简洁。不过,应该能够推断出任何反射场景。还是有点臭太过去了

    var props =  bindingContext.ModelType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).ToList();

    bindingContext.ModelType.GetInterfaces()
                      .ToList()
                      .ForEach(i => props.AddRange(i.GetProperties()));

    foreach (var property in props)

回答by Douglas

Type.GetInterfacesreturns the flattened hierarchy, so there is no need for a recursive descent.

Type.GetInterfaces返回扁平的层次结构,因此不需要递归下降。

The entire method can be written much more concisely using LINQ:

使用 LINQ 可以更简洁地编写整个方法:

public static IEnumerable<PropertyInfo> GetPublicProperties(this Type type)
{
    if (!type.IsInterface)
        return type.GetProperties();

    return (new Type[] { type })
           .Concat(type.GetInterfaces())
           .SelectMany(i => i.GetProperties());
}

回答by sjb-sjb

Responding to @douglas and @user3524983, the following should answer the OP's question:

回应@douglas 和@user3524983,以下内容应回答OP 的问题:

    static public IEnumerable<PropertyInfo> GetPropertiesAndInterfaceProperties(this Type type, BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance)
    {
        if (!type.IsInterface) {
            return type.GetProperties( bindingAttr);
        }

        return type.GetInterfaces().Union(new Type[] { type }).SelectMany(i => i.GetProperties(bindingAttr)).Distinct();
    }

or, for an individual property:

或者,对于单个财产:

    static public PropertyInfo GetPropertyOrInterfaceProperty(this Type type, string propertyName, BindingFlags bindingAttr = BindingFlags.Public|BindingFlags.Instance)
    {
        if (!type.IsInterface) {
            return type.GetProperty(propertyName, bindingAttr);
        }

        return type.GetInterfaces().Union(new Type[] { type }).Select(i => i.GetProperty( propertyName, bindingAttr)).Distinct().Where(propertyInfo => propertyInfo != null).Single();
    }

OK next time I'll debug it before posting instead of after :-)

好的,下次我会在发布之前而不是之后调试它:-)