代码之家  ›  专栏  ›  技术社区  ›  Sarah Vessels

如何获取应用自定义属性的成员?

  •  54
  • Sarah Vessels  · 技术社区  · 15 年前

    我正在创建一个 custom attribute new StackTrace().GetFrame(1).GetMethod() 在我的自定义属性构造函数中查看哪个方法调用了属性构造函数,但现在我不确定这会给我带来什么。如果属性应用于属性,该怎么办?将 GetMethod() MethodBase 那处房产的实例?在C#中是否有其他方法获取应用了属性的成员?

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
        AllowMultiple = true)]
    public class MyCustomAttribute : Attribute
    

    更新: 好吧,我可能问错问题了。在自定义属性类中,如何获取应用自定义属性的成员(或包含该成员的类)? Aaronaught 建议不要在堆栈中查找应用了我的属性的类成员,但我如何从属性的构造函数中获取这些信息呢?

    4 回复  |  直到 8 年前
        1
  •  42
  •   mcwyrm    7 年前

    由于堆栈框架和方法的工作方式似乎存在很多混乱,下面是一个简单的演示:

    static void Main(string[] args)
    {
        MyClass c = new MyClass();
        c.Name = "MyTest";
        Console.ReadLine();
    }
    
    class MyClass
    {
        private string name;
    
        void TestMethod()
        {
            StackTrace st = new StackTrace();
            StackFrame currentFrame = st.GetFrame(1);
            MethodBase method = currentFrame.GetMethod();
            Console.WriteLine(method.Name);
        }
    
        public string Name
        {
            get { return name; }
            set
            {
                TestMethod();
                name = value;
            }
        }
    }
    

    C#中的属性是语法糖的一种形式。它们在IL中编译为getter和setter方法,有些.NET语言甚至可能无法将它们识别为属性-属性解析完全按照约定完成,IL规范中没有任何规则。

    现在,让我们假设您有一个非常好的理由让一个程序想要检查它自己的堆栈(还有 极少数 这样做的实际原因)。你到底为什么希望它在属性和方法上表现得不同?

    属性背后的全部理由是它们是一种元数据。如果你想要一个不同的行为,编码它 . 如果一个属性可以表示两种不同的东西,这取决于它是应用于方法还是属性,那么您应该 两个属性 . 将第一个目标设置为 AttributeTargets.Method 第二个是 AttributeTargets.Property . 简单。

    但是再一次,遍历自己的堆栈从调用方法中获取一些属性,充其量是危险的。在某种程度上,您正在冻结程序的设计,这使得任何人都很难扩展或重构程序。这不是通常使用属性的方式。更多 适当的 例如,类似于验证属性:

    public class Customer
    {
        [Required]
        public string Name { get; set; }
    }
    

    public void Validate(object o)
    {
        Type t = o.GetType();
        foreach (var prop in
            t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            if (Attribute.IsDefined(prop, typeof(RequiredAttribute)))
            {
                object value = prop.GetValue(o, null);
                if (value == null)
                    throw new RequiredFieldException(prop.Name);
            }
        }
    }
    

    换句话说,您正在检查 但是你不一定知道这种类型的。XML属性、数据协定属性,甚至属性属性—几乎.NET Framework中的所有属性都是以这种方式使用的,以实现一些与XML相关的动态功能 实例的类型 方案状况 或者堆栈上发生了什么。在创建堆栈跟踪时,您实际上不太可能控制这一点。

    所以我再次建议你 不要 使用堆栈遍历方法,除非您有非常好的理由这样做,而您还没有告诉我们。否则,你很可能会发现自己处于一个受伤的世界。

        2
  •  44
  •   Scott Dorman    15 年前

    属性提供元数据,但对它们所修饰的对象(类、成员等)一无所知。另一方面,被修饰的事物可以要求它被修饰的属性。

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, 
        AllowMultiple = true)] 
    public class MyCustomAttribute : Attribute
    {
       Type type;
    
       public MyCustomAttribute(Type type)
       {
          this.type = type;
       }
    }
    
        3
  •  5
  •   Manfred    8 年前

    GetMethod 将始终返回函数名。如果它是一个属性,您将获得 get_PropertyName set_PropertyName .

        4
  •  4
  •   alexdej    15 年前

    自定义属性由一些代码激活,这些代码在ICCustomAttributeProvider(反射对象)上调用GetCustomAttributes方法,ICCustomAttributeProvider表示应用属性的位置。因此,对于属性,一些代码将获取属性的PropertyInfo,然后对该属性调用GetCustomAttributes。

    public interface ICustomValidationAttribute
    {
        void Attach(ICustomAttributeProvider foundOn);
    }
    

    您的代码可以在(例如)类型上查找此接口:

    var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true);
    foreach (ICustomValidationAttribute validator in validators)
    {
         validator.Attach(type);
    }
    

    (假设您将遍历整个反射图,并对每个ICCustomAttribute Provider执行此操作)。有关.net FX中使用的类似方法的示例,您可以查看WCF的“行为”(IServiceBehavior、IOperationBehavior等)。

    更新:.NETFX确实有一种通用的拦截框架,但基本上没有以ContextBoundObject和ContextAttribute的形式记录在案。您可以在web上搜索一些将其用于AOP的示例。