我正在用C#创建一个custom attribute,我想根据属性是应用于方法还是应用于属性来做不同的事情。起初,我打算在自定义属性构造函数中执行new StackTrace().GetFrame(1).GetMethod()
,看看是什么方法调用了属性构造函数,但现在我不确定这会给我带来什么。如果该属性应用于某个属性,情况会怎样?GetMethod()
会为该属性返回一个MethodBase
实例吗?在C#中,有没有不同的方法来获取应用了属性的成员?
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
更新:好吧,我可能问错问题了。在自定义属性类中,如何获取应用了自定义属性的成员(或包含该成员的类)?Aaronaught建议不要遍历堆栈来查找应用了该属性的类成员,但否则我如何从属性的构造函数中获取此信息?
发布于 2010-01-31 03:43:12
由于堆栈框架和方法的工作原理似乎有很多混乱之处,下面是一个简单的演示:
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
。很简单。
但是,再说一次,遍历自己的堆栈从调用方法中提取一些属性充其量也是危险的。在某种程度上,你冻结了你的程序的设计,使得任何人扩展或重构它变得更加困难。这不是通常使用属性的方式。一个更合适的示例是类似于验证属性的内容:
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框架中的几乎所有属性都是这样使用的,以实现一些功能,这些功能相对于实例的类型是动态的,而与程序的状态或堆栈上的内容无关。在创建堆栈跟踪时,您实际上不太可能对此进行控制。
因此,我再次建议您不要使用堆栈遍历方法,除非您有一个非常好的理由这样做,而您还没有告诉我们。否则,你很可能会发现自己身处一个充满伤害的世界。
如果您一定要这样做(不要说我们没有警告您),那么使用两个属性,一个可以应用于方法,另一个可以应用于属性。我想您会发现这比使用单个超属性要容易得多。
发布于 2010-01-31 04:47:38
属性提供元数据,并且不知道任何关于事物(类、成员等)的信息。他们在装饰。另一方面,被装饰的东西可以请求用来装饰它的属性。
如果您必须知道正在修饰的对象的类型,则需要在其构造函数中显式地将其传递给您的属性。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
Type type;
public MyCustomAttribute(Type type)
{
this.type = type;
}
}
发布于 2010-01-31 02:46:36
GetMethod
将始终返回函数名。如果它是一个属性,你将得到get_PropertyName
或set_PropertyName
。
属性基本上是一种方法类型,因此当您实现属性时,编译器会在生成的set_中创建两个单独的函数,一个是get_方法,一个是a MSIL方法。这就是在堆栈跟踪中收到这些名称的原因。
https://stackoverflow.com/questions/2168942
复制相似问题