首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何获取应用了自定义属性的成员?

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

Stack Overflow用户
提问于 2010-01-31 02:34:53
回答 4查看 51.4K关注 0票数 64

我正在用C#创建一个custom attribute,我想根据属性是应用于方法还是应用于属性来做不同的事情。起初,我打算在自定义属性构造函数中执行new StackTrace().GetFrame(1).GetMethod(),看看是什么方法调用了属性构造函数,但现在我不确定这会给我带来什么。如果该属性应用于某个属性,情况会怎样?GetMethod()会为该属性返回一个MethodBase实例吗?在C#中,有没有不同的方法来获取应用了属性的成员?

代码语言:javascript
复制
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
    AllowMultiple = true)]
public class MyCustomAttribute : Attribute

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

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-01-31 03:43:12

由于堆栈框架和方法的工作原理似乎有很多混乱之处,下面是一个简单的演示:

代码语言:javascript
复制
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;
        }
    }
}

此程序的输出将为:

set_Name

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

现在,假设您有一个非常好的理由让程序检查自己的堆栈(这样做的实际理由很少)。为什么你希望它在属性和方法上有不同的行为呢?

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

但是,再说一次,遍历自己的堆栈从调用方法中提取一些属性充其量也是危险的。在某种程度上,你冻结了你的程序的设计,使得任何人扩展或重构它变得更加困难。这不是通常使用属性的方式。一个更合适的示例是类似于验证属性的内容:

代码语言:javascript
复制
public class Customer
{
    [Required]
    public string Name { get; set; }
}

然后,您的验证器代码,它对传入的实际实体一无所知,可以这样做:

代码语言:javascript
复制
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框架中的几乎所有属性都是这样使用的,以实现一些功能,这些功能相对于实例的类型是动态的,而与程序的状态或堆栈上的内容无关。在创建堆栈跟踪时,您实际上不太可能对此进行控制。

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

如果您一定要这样做(不要说我们没有警告您),那么使用两个属性,一个可以应用于方法,另一个可以应用于属性。我想您会发现这比使用单个超属性要容易得多。

票数 42
EN

Stack Overflow用户

发布于 2010-01-31 04:47:38

属性提供元数据,并且不知道任何关于事物(类、成员等)的信息。他们在装饰。另一方面,被装饰的东西可以请求用来装饰它的属性。

如果您必须知道正在修饰的对象的类型,则需要在其构造函数中显式地将其传递给您的属性。

代码语言:javascript
复制
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, 
    AllowMultiple = true)] 
public class MyCustomAttribute : Attribute
{
   Type type;

   public MyCustomAttribute(Type type)
   {
      this.type = type;
   }
}
票数 44
EN

Stack Overflow用户

发布于 2010-01-31 02:46:36

GetMethod将始终返回函数名。如果它是一个属性,你将得到get_PropertyNameset_PropertyName

属性基本上是一种方法类型,因此当您实现属性时,编译器会在生成的set_中创建两个单独的函数,一个是get_方法,一个是a MSIL方法。这就是在堆栈跟踪中收到这些名称的原因。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2168942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档