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