因为关于堆栈帧和方法如何工作的混淆似乎很多,所以这里有一个简单的演示:
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框架中几乎所有的属性都是这样使用的,用于实现某些与实例类型动态相关但与程序状态或堆栈上存在内容无关的功能。在创建堆栈跟踪时,很少有可能真正控制它。
因此,我再次建议您除非有非常充分的理由尚未告知我们,否则不要使用堆栈遍历方法。否则,您可能会发现自己处于一种痛苦的世界中。
如果您绝对必须(别说我们没警告过您),请使用两个属性,一个可应用于方法,另一个可应用于属性。我认为您会发现这比一个超级属性更容易使用。
GetCustomAttribute[s]
方法中获取属性的信息。 - Aaronaught