105 votes

GetProperties () pour renvoyer toutes les propriétés d'une hiérarchie d'héritage d'interface

En supposant que la suite hypothétique hiérarchie d'héritage:

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

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

L'utilisation de la réflexion et de faire l'appel suivant:

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

ne donnent les propriétés de l'interface IB, ce qui est "Name".

Si nous devions faire un test similaire sur le code suivant,

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

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

l'appel typeof(B).GetProperties(BindingFlags.Public | BindingFlags.Instance) retournera un tableau de PropertyInfo objets pour "ID" et "Name".

Est-il un moyen facile de trouver toutes les propriétés dans la hiérarchie d'héritage pour les interfaces comme dans le premier exemple?

114voto

mythz Points 54874

J'ai modifié l'exemple de code de @Marc Gravel en une méthode d'extension utile qui encapsule les classes et les interfaces. Il ajoute également les propriétés d'interface en premier qui, je crois, est le comportement attendu.

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

15voto

Marc Gravell Points 482669

Les hiérarchies d'interface sont pénibles - elles ne "héritent" pas vraiment en tant que telles, car vous pouvez avoir plusieurs "parents" (à défaut d'un meilleur terme).

"Aplatissement" (encore une fois, ce n'est pas tout à fait le terme qui convient), la hiérarchie pourrait impliquer de vérifier toutes les interfaces implémentées par l'interface et de travailler à partir de là ...

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

3voto

Wolf5 Points 2906

Une solution de contournement est exactement décrite dans le même problème: http://saftsack.fs.uni-bayreuth.de/~dun3/archives/weird-surprise-while-using-flattenhierarchy-on-interfaces/160.html

FlattenHierarchy ne fonctionne pas btw. (seulement sur les vars statiques. le dit en intellisense)

Solution de contournement. Méfiez-vous des doublons.

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

1voto

cela a fonctionné joliment pour moi dans un classeur de modèle MVC personnalisé. Devrait pouvoir extrapoler à n'importe quel scénario de réflexion cependant. Encore genre de puant que c'est trop passer

     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)
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X