2017-02-01 11 views
3

Я создал настраиваемый атрибут с именем someAttribute.
Это логический элемент с именем Skip:Как использовать атрибуты 'внутри метода

public class someAttribute : Attribute 
{ 
    public bool Skip { get; set; } 
} 

В Main я инициализирован элемент Skip со значением true для метода foo().

Затем я звоню функцию foo() которая имеет атрибут [someAttribute()], и я хочу, чтобы проверить, если член Skip был инициализирован:

[someAttribute()] 
private static int foo() 
{ 
    if(Skip) 
    { 
     return 0; 
    } 

    return 1; 
} 

я получил ошибку "Название„Пропустить“не существует в текущий контекст ".
enter image description here

Как проверить элементы атрибута внутри метода, использующего этот атрибут?

Мой полный код:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 

namespace ConsoleApplication1 
{ 
    class ProgramTest 
    { 
     [someAttribute()] 
     private static int foo() 
     { 
      if(Skip) 
      { 
       return 0; 
      } 

      return 1; 
     } 

     public class someAttribute : Attribute 
     { 
      public bool Skip { get; set; } 
     } 

     public static void initAttributes() 
     { 
      var methods = Assembly.GetExecutingAssembly().GetTypes().SelectMany(t => t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) 
      .Where(method => Attribute.IsDefined(method, typeof(someAttribute))); 

      foreach (MethodInfo methodInfo in methods) 
      { 
       IEnumerable<someAttribute> SomeAttributes = methodInfo.GetCustomAttributes<someAttribute>(); 
       foreach (var attr in SomeAttributes) 
       { 
        attr.Skip = true; 
       } 
      } 
     } 
     static void Main(string[] args) 
     { 
      initAttributes(); 
      int num = foo(); 
     } 
    } 
} 

EDIT:
Я добавил BindingFlags.Static для того, чтобы refelction, чтобы получить статическую функцию foo().

+0

Возможный дубликат [Отражение - получить имя атрибута и значение на имущество] (http://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property) – HimBromBeere

+1

Я полагаю, вам понадобится 'BindingFlags.Static | BindingFlags.NonPublic' как ваш 'foo'-метод -' private static'. – HimBromBeere

+0

Я отредактировал код и добавил его, спасибо. – E235

ответ

1

Вы можете получить атрибут с чем-то вроде этого:

[someAttribute()] 
private static int foo() 
{ 
    if (GetCurrentMethodAttribute<someAttribute>().Skip) 
    { 
     return 0; 
    } 
    return 1; 
} 

[MethodImpl(MethodImplOptions.NoInlining)] 
private static T GetCurrentMethodAttribute<T>() where T : Attribute 
{ 
    return (T)new StackTrace().GetFrame(1).GetMethod().GetCustomAttribute(typeof(T)); 
} 

Во всяком случае, в методе initAttributes(), когда вы делаете Assembly.GetExecutingAssembly().GetTypes().SelectMany, вы не получите метод foo, потому что это static, так что вы должны также используйте BindingFlags.Static.

Кроме того, you cannot set an attribute value at runtime, поэтому изменения, внесенные initAttributes не будут «видеть», когда вы извлекаете атрибут (так Пропустить свойство будет false)

+0

Устранена проблема с настройкой свойств атрибутов во время выполнения. Но я думаю, что подход трассировки стека может завершиться неудачно, если компилятор встраивает метод или из-за других оптимизаций. –

1

Вы можете использовать отражение для достижения этой цели:

[someAttribute()] 
private static int foo() 
{ 
    if (typeof(ProgramTest).GetMethod(nameof(foo)). 
         GetCustomAttribute<someAttribute>()?.Skip ?? false) 
     return 0; 

    return 1; 
} 

Это получает MethodInfo для foo и проверяет, что метод имеет someAttribute. Если это так, он проверяет свойство Skip этого экземпляра атрибута.

В вашем случае GetMethod() потребуется еще несколько аргументов, так как foo - private и static. Если у вас есть несколько перегруженных foo вам также необходимо указать типы параметров:

private static int foo() 
{ 
    // some foo code 
    return 1; 
} 

[someAttribute(Skip=true)] 
private static int foo(int arg) 
{ 
    if (typeof(ProgramTest).GetMethod(nameof(foo), 
         BindingFlags.Static | BindingFlags.NonPublic, 
         null, // use default binder 
         new Type[] {typeof(int)}, // list of parameter types 
         null) // array of parameter modifiers 
       .GetCustomAttribute<someAttribute>()?.Skip ?? false) 
     return 0; 
    return arg; 
} 

(Примечание: В предыдущем редактировании я предложил ConditionalAttribute вместо этого, но, очевидно, это не относится к Непустым методам).