Как я получаю участника, к которому был применен мой пользовательский атрибут?

Я создаю пользовательский атрибут в C#, и я хочу сделать разные вещи на основе того, применяется ли атрибут к методу по сравнению со свойством. Сначала я собирался сделать new StackTrace().GetFrame(1).GetMethod() в моем конструкторе пользовательского атрибута для наблюдения, какой метод, названный конструктором атрибута, но теперь, я не уверен, что это даст мне. Что, если атрибут был применен к свойству? Был бы GetMethod() возвратите a MethodBase экземпляр для того свойства? Существует ли другой способ получить участника, к которому атрибут был применен в C#?

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property,
    AllowMultiple = true)]
public class MyCustomAttribute : Attribute

Обновление: хорошо, я, возможно, задавал неправильный вопрос. Из класса пользовательского атрибута, как я получаю участника (или класс, содержащий участника), к которому был применен мой пользовательский атрибут? Aaronaught предложил против хождения по стеку найти участника класса, к которому мой атрибут был применен, но как еще я получу эту информацию из конструктора моего атрибута?

56
задан Community 23 May 2017 в 12:03
поделиться

4 ответа

Поскольку кажется, что существует большая путаница относительно того, как работают фреймы и методы стека, вот простая демонстрация:

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, атрибуты контракта данных, даже атрибуты атрибутов - почти все атрибуты в .NET Framework используются таким образом, чтобы реализовать некоторые функциональные возможности, которые являются динамическими по отношению к типу экземпляра , но не по отношению к состояние программы или то, что находится в стеке. Очень маловероятно, что вы действительно контролируете это в момент создания трассировки стека.

Итак, я снова порекомендую вам не использовать подход обхода стека, если у вас нет очень веской причины для этого, о которой вы еще не сказали нам. В противном случае вы, скорее всего, попадете в мир боли.

Если вы абсолютно обязаны (не говорите, что мы вас не предупреждали), используйте два атрибута, один из которых может применяться к методам, а другой - к свойствам. Думаю, вы обнаружите, что работать с этим намного проще, чем с одним супер-атрибутом.

41
ответ дан 26 November 2019 в 17:25
поделиться

В MySql необходимо разрешить пользователю доступ с localhost явным образом. Вот пример (взятый из здесь ):

mysql> grant usage on *.* to amarokuser@localhost identified by 'amarokpasswd';
mysql> grant all privileges on amarokdb.* to amarokuser@localhost ;
-121--3665266-

Вместо sprintf и vprintf вы хотите использовать:

snprintf(buffer, buffer_size, fmt_string, args, ...);
vsnprintf(buffer, buffer_size, fmt_string, valist);

Вместо strcpy, strncpy, strcat и strncat вы хотите нам:

strlcpy(dest, src, dest_size);
strlcat(dest, src, dest_size);

Есть один важный путь, что strn функции нельзя заменить Если требуется скопировать не-0 завершенные последовательности, функции strn позволяют сделать это, установив для длины меньшее значение объема копии и размера целевого буфера. Функции strl не делают этого и работают только тогда, когда исходная последовательность заканчивается 0.

Не уверен, как fopen или vfprintf считаются небезопасными.

-121--2881569-

пользовательские атрибуты активируются некоторым кодом, вызывающим метод GetCustomAttributes в ICustomAttribityProvider (объект отражения), который представляет расположение, в котором применяется атрибут. Поэтому в случае свойства какой-либо код получает PropertyInfo для свойства, а затем вызывает GetCustomAttributes для этого.

Если требуется создать некоторую структуру проверки, необходимо написать код, проверяющий типы и членов на наличие пользовательских атрибутов. Например, можно иметь интерфейс, реализующий атрибуты для участия в структуре проверки. Может быть так же просто, как и следующее:

public interface ICustomValidationAttribute
{
    void Attach(ICustomAttributeProvider foundOn);
}

Ваш код может искать это интефейс на (например) Тип:

var validators = type.GetCustomAttributes(typeof(ICustomValidationAttribute), true);
foreach (ICustomValidationAttribute validator in validators)
{
     validator.Attach(type);
}

(вероятно, вы бы прошли весь график отражения и сделали это для каждого ICustomAttribureProvider). Пример аналогичного подхода в действии в .net FX можно посмотреть на «поведение» WCF (IServityBehavior, IOperationBehavior и т.д.).

Обновление: .net FX действительно имеет своего рода общую цель, но в основном недокументированную структуру перехвата в виде ContextBoundObject и ContextAttribute. В Интернете можно найти примеры его использования для AOP.

4
ответ дан 26 November 2019 в 17:25
поделиться

GetMethod всегда будет возвращать вам имя функции. Если это свойство, вы получите либо get_Propertyname или Set_PropertyName .

Недвижимость в основном является типом способа, поэтому при реализации свойства компилятор создает две отдельные функции в результате MSIL, a get_ и a a set_ методы. Вот почему в стоп-следах вы получаете эти имена.

4
ответ дан 26 November 2019 в 17:25
поделиться

Атрибуты предоставляют метаданные и ничего не знают о том, что (класс, член и т. Д.) Они украшают. С другой стороны, декорированная вещь может попросить атрибуты оно украшено.

Если вы должны знать, что тип оформления, вам понадобится явно передавать его к своему атрибуту в своем конструкторе.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, 
    AllowMultiple = true)] 
public class MyCustomAttribute : Attribute
{
   Type type;

   public MyCustomAttribute(Type type)
   {
      this.type = type;
   }
}
40
ответ дан 26 November 2019 в 17:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: