Getproperties() to Return All Properties for an Interface Inheritance Hierarchy

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

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.

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);
}

Reflecting over all properties of an interface, including inherited ones?

An answer of sorts is to be found in an annotation to the .NET framework version 3.5-specific MSDN page on GetProperties(BindingFlags bindingFlags) :

Passing BindingFlags.FlattenHierarchy
to one of the Type.GetXXX methods,
such as Type.GetMembers, will not
return inherited interface members
when you are querying on an interface
type itself.

[...]

To get the inherited members, you need
to query each implemented interface
for its members.

Example code is also included. This comment was posted by a Microsoftie, so I would say you can trust it.

GetProperties for inherited/child class with appropriate BindingFlags does not return expected properties


public readonly Guid Id is a field, not a property. Use the GetField method instead:

typeof(ChildClass).GetField("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

You can check to see if it is readonly by looking at the IsInitOnly property of the FieldInfo class.

var result = typeof(ChildClass).GetField("Id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Assert.IsTrue(result.IsInitOnly);

Using attribute of inherited property from an interface

Child does not have any custom attributes, ITest has them, so you will have to call GetCustomAttributes on the members of ITest.

There is a difference between inheritance and implementation. Inheritance would be fine if Child was derived from some base class that had a y property decorated with My1Attribute.

In your case, Child implements ITest and ITest is a different type, outside of the inheritance hierarchy.

void Main()
{
var my1Attribute = typeof(ITest).GetProperty("y").GetCustomAttribute(typeof(My1Attribute)) as My1Attribute;
Console.WriteLine(my1Attribute.x); // Outputs: 0
}

[AttributeUsage(AttributeTargets.Property, Inherited = true)]
class My1Attribute : Attribute
{
public int x { get; set; }
}

interface ITest
{
[My1]
int y { get; set; }
}

class Child : ITest
{
public Child() { }

public int y { get; set; }
}

Reflection : Getting members from inherited interface, but not from inherited class

You can go about this in a number of ways, depending on your exact aim.

One idea is to get all properties normally then filter out those coming from class A using DeclaringType, e.g.

var typeOfA = typeof(A);
var notFromA = allMembers.Where(
p => p.DeclaringType != typeOfA && !p.DeclaringType.IsSubclassOf(typeOfA));

Or of course you can simply ignore the base class completely and get only the members coming from implemented interfaces, e.g.

var members = typeof(B).GetInterfaces().SelectMany(i => i.GetMembers());

This will give you all members of B that are implementations of interface members -- not necessarily all of B's declared members, and it will include interface members that A has implemented.

In general the correct way to do this depends on the exact requirements, but I feel the question is not precise enough in its current form.



Related Topics



Leave a reply



Submit