Поскольку в отношении работы стековых фреймов и методов возникает большая путаница, приведем простую демонстрацию:
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, и возможно, что некоторые языки .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, атрибуты Контракта данных, даже атрибуты Attribute - почти все атрибуты в .NET Framework используются таким образом, чтобы реализовать некоторые функциональные возможности, которые являются динамическими по отношению к типу экземпляра , но не по отношению к состояние программы или что находится в стеке. Маловероятно, что вы фактически управляете этим в точке, где вы создаете трассировку стека.
Итак, я снова рекомендую, чтобы вы не использовали подход с использованием стека, если у вас нет для этого веской причины, о которой вы еще не сказали нам. В противном случае вы, вероятно, окажетесь в мире боли.
Если вам абсолютно необходимо (не говорите, что мы вас не предупреждали), тогда используйте два атрибута, один из которых может применяться к методам, а другой - к свойствам. Я думаю, вы обнаружите, что с ним гораздо проще работать, чем с одним супер-атрибутом.