Comment utiliser la réflexion pour que les propriétés implémentent explicitement une interface?

StackOverflow https://stackoverflow.com/questions/278997

Question

Plus précisément, si j'ai:

public class TempClass : TempInterface
{

    int TempInterface.TempProperty
    {
        get;
        set;
    }
    int TempInterface.TempProperty2
    {
        get;
        set;
    }

    public int TempProperty
    {
        get;
        set;
    }
}

public interface TempInterface
{
    int TempProperty
    {
        get;
        set;
    }
    int TempProperty2
    {
        get;
        set;
    }
}

Comment utiliser la réflexion pour obtenir toutes les propriétés de propertyInfos implémentant explicitement TempInterface?

Merci.

Était-ce utile?

La solution 5

J'ai dû modifier la réponse de Jacob Carpenter, mais cela fonctionne bien. nobugz fonctionne aussi mais Jacobs est plus compact.

var explicitProperties =
from method in typeof(TempClass).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where method.IsFinal && method.IsPrivate
select method;

Autres conseils

Je pense que la classe que vous recherchez est System.Reflection.InterfaceMapping.

Type ifaceType = typeof(TempInterface);
Type tempType = typeof(TempClass);
InterfaceMapping map = tempType.GetInterfaceMap(ifaceType);
for (int i = 0; i < map.InterfaceMethods.Length; i++)
{
    MethodInfo ifaceMethod = map.InterfaceMethods[i];
    MethodInfo targetMethod = map.TargetMethods[i];
    Debug.WriteLine(String.Format("{0} maps to {1}", ifaceMethod, targetMethod));
}

La propriété getter et setter d'une propriété d'interface implémentée explicitement possède un attribut inhabituel. Sa propriété IsFinal est True, même si ce n'est pas un membre d'une classe scellée. Essayez ce code pour vérifier mon assertion:

  foreach (AssemblyName name in Assembly.GetEntryAssembly().GetReferencedAssemblies()) {
    Assembly asm = Assembly.Load(name);
    foreach (Type t in asm.GetTypes()) {
      if (t.IsAbstract) continue;
      foreach (MethodInfo mi in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) {
        int dot = mi.Name.LastIndexOf('.');
        string s = mi.Name.Substring(dot + 1);
        if (!s.StartsWith("get_") && !s.StartsWith("set_")) continue;
        if (mi.IsFinal)
          Console.WriteLine(mi.Name);
      }
    }
  }

Voici une solution modifiée basée sur la mise en oeuvre indiquée dans cet article de blog :

var explicitProperties =
    from prop in typeof(TempClass).GetProperties(
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)
    let getAccessor = prop.GetGetMethod(true)
    where getAccessor.IsFinal && getAccessor.IsPrivate
    select prop;

foreach (var p in explicitProperties)
    Console.WriteLine(p.Name);

Création sur réponse de MrKurt :

var targetMethods =
    from iface in typeof(TempClass).GetInterfaces()
    from method in typeof(TempClass).GetInterfaceMap(iface).TargetMethods
    select method;

var explicitProps =
    from prop in typeof(TempClass).GetProperties(BindingFlags.Instance |
                                                 BindingFlags.NonPublic)
    where targetMethods.Contains(prop.GetGetMethod(true)) ||
          targetMethods.Contains(prop.GetSetMethod(true))
    select prop;

C'est trop complexe. Vous devez réfléchir aux méthodes / propriétés du type d'interface, voir si elles existent dans votre type de classe et les comparer pour voir si elles sont identiques. quand ils existent.

Si quelque chose se trouve dans l'interface mais pas le type que vous testez, il s'agit d'une implémentation explicite. Si c'est dans les deux, mais différent entre les deux, c'est une interface explicite.

Il manque un filtre dans le code de Jacob:

        var props = typeof(TempClass).GetInterfaces().Where(i => i.Name=="TempInterface").SelectMany(i => i.GetProperties());
        foreach (var prop in props)
            Console.WriteLine(prop);

Cela semble un peu douloureux sans raison apparente!

Ma solution concerne le cas où vous connaissez le nom de la propriété que vous recherchez et qui est assez simple.

J'ai un cours pour rendre la réflexion un peu plus facile que je n'ai eu qu'à ajouter ce cas à:

public class PropertyInfoWrapper
{
    private readonly object _parent;
    private readonly PropertyInfo _property;

    public PropertyInfoWrapper(object parent, string propertyToChange)
    {
        var type = parent.GetType();
        var privateProperties= type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);

        var property = type.GetProperty(propertyToChange) ??
                       privateProperties.FirstOrDefault(p => UnQualifiedNameFor(p) == propertyName);

        if (property == null)
            throw new Exception(string.Format("cant find property |{0}|", propertyToChange));

        _parent = parent;
        _property = property;
    }

    private static string UnQualifiedNameFor(PropertyInfo p)
    {
        return p.Name.Split('.').Last();
    }

    public object Value
    {
        get { return _property.GetValue(_parent, null); }
        set { _property.SetValue(_parent, value, null); }
    }
}

Vous ne pouvez pas faire == sur le nom car les propriétés implémentées explicitement ont des noms complets.

GetProperties a besoin des deux indicateurs de recherche pour accéder aux propriétés privées.

Une classe d'assistance simple qui pourrait aider:

public class InterfacesPropertiesMap
{
    private readonly Dictionary<Type, PropertyInfo[]> map;

    public InterfacesPropertiesMap(Type type)
    {
        this.Interfaces = type.GetInterfaces();
        var properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);

        this.map = new Dictionary<Type, PropertyInfo[]>(this.Interfaces.Length);

        foreach (var intr in this.Interfaces)
        {
            var interfaceMap = type.GetInterfaceMap(intr);
            this.map.Add(intr, properties.Where(p => interfaceMap.TargetMethods
                                                    .Any(t => t == p.GetGetMethod(true) ||
                                                              t == p.GetSetMethod(true)))
                                         .Distinct().ToArray());
        }
    }

    public Type[] Interfaces { get; private set; }

    public PropertyInfo[] this[Type interfaceType]
    {
        get { return this.map[interfaceType]; }
    }
}

Vous obtiendrez des propriétés pour chaque interface, même explicitement implémentée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top