代码之家  ›  专栏  ›  技术社区  ›  Paul Milla

反射获取接口属性的实现属性

  •  1
  • Paul Milla  · 技术社区  · 6 年前

    我有一个在属性上定义了自定义属性的接口,我想从该接口的派生实例中检索相关属性。

    public interface ITopicProcessor<T>
    {
        [TopicKey]
        string TopicName { get; }
    
        [OtherAttribute]
        string OtherProperty { get; }
    
        void Process(T message);
    }
    
    public class MyClassProcessor : ITopicProcessor<MyClass>
    {
        public string TopicName => "MyTopic";
    
        public string OtherProperty => "Irrelevant";
    
        public void Process(MyClass message)
        {
        }
    }
    

    我可以接近以下内容-主要问题是派生接口类型似乎没有与泛型类型定义相同的自定义属性。我敢肯定,部分原因是需要使用底层方法实现,而不是直接使用属性值

    // iType is typeof(ITopicProcessor<MyClass>)
    // I also have access to the generic type definition if need be - i.e. typeof(ITopicProcessor<>)
    Func<Type, string> subscriberTypeToTopicKeySelector = iType =>
    {
        // Creating an instance via a dependency injection framework
        var instance = kernel.Get(iType);
        var classType = instance.GetType();
    
        var interfaceMap = classType.GetInterfaceMap(iType);
        // interfaceMap.InterfaceMethods contains underlying get_property method, but no custom attributes
        var interfaceMethod = interfaceMap.InterfaceMethods
                                          .Where(x => x.HasAttribute<TopicKeyAttribute>())
                                          .ToList();
        var classMethodInfo = interfaceMap.TargetMethods[Array.IndexOf(interfaceMap.InterfaceMethods, interfaceMethod)];
    
        return classMethodInfo.Invoke(instance, BindingFlags.Default, null, null, CultureInfo.CurrentCulture)
                              .ToString();
    };
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   ZorgoZ    6 年前

    实现接口不是从类继承的。这就是为什么这样的通知不会从接口传播到类。参见:bradwilson.typepad.com/blog/2011/08/interface-attributes-class-attributes.html

    但也有解决办法: Can a C# class inherit attributes from its interface?

        2
  •  0
  •   Paul Milla    6 年前

    离开@thehenny的注释,我得到了一些不仅有效,而且可以处理应用于属性或方法的[TopicKey]属性的东西。为了满足我的需要,我只希望它在一个界面中出现一次,但是其他人可以根据自己的需要扩展这个解决方案

    subscriberTypeToTopicKeySelector = iType =>
    {
        var instance = kernel.Get(iType);
        var classType = instance.GetType();
        var interfaceMap = classType.GetInterfaceMap(iType);
    
        var iTopicKeyPropertyGetMethods = iType.GetProperties()
                                               .Where(x => x.HasAttribute<TopicKeyAttribute>())
                                               .Select(x => x.GetMethod);
        var iTopicKeyMethods = iType.GetMethods()
                                    .Where(x => x.HasAttribute<TopicKeyAttribute>())
                                    .Union(iTopicKeyPropertyGetMethods);
    
        var indexOfInterfaceMethod = Array.IndexOf(interfaceMap.InterfaceMethods, iTopicKeyMethods.Single());
        var classMethodInfo = interfaceMap.TargetMethods[indexOfInterfaceMethod];
    
        return classMethodInfo.Invoke(instance, BindingFlags.Default, null, null, CultureInfo.CurrentCulture)
                              .ToString();
    };