簡體   English   中英

如何使用反射來獲取顯式實現接口的屬性?

[英]How do I use reflection to get properties explicitly implementing an interface?

更具體地說,如果我有:

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

如何使用反射來獲取顯式實現TempInterface的屬性的所有propertyInfos?

謝謝。

我認為您正在尋找的類是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));
}

顯式實現的接口屬性的屬性getter和setter具有不尋常的屬性。 它的IsFinal屬性是True,即使它不是密封類的成員。 試試這段代碼來驗證我的斷言:

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

以下是基於此博客文章中給出的實現的修改后的解決方案:

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

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;

這太復雜了。 您必須反映Interface類型的方法/屬性,看它們是否存在於您的類類型中,並比較它們以確定它們是否存在時是否“相同”。

如果界面中有某些內容但不是您正在測試的類型,則它是一個顯式實現。 如果它在兩者之間,但兩者之間不同,則它是一個顯式接口。

我不得不修改雅各布卡彭特的答案,但效果很好。 nobugz也有效,但Jacobs更緊湊。

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

一個簡單的幫助類可以幫助:

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

您將獲得每個接口的屬性,甚至是明確實現的。

雅各布的代碼缺少一個過濾器:

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

沒有明顯的原因,這似乎有點痛苦!

我的解決方案是您知道要查找的屬性的名稱並且非常簡單的情況。

我有一個讓反射變得容易的類,我只需要將這個案例添加到:

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

您不能在名稱上執行==因為顯式實現的屬性具有完全限定名稱。

GetProperties需要兩個搜索標志來獲取私有屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM