2017-02-01 3 views
3

Ich erstellte benutzerdefinierte Attribut namens someAttribute.
Es boolean Mitglied hat Skip genannt:So verwenden Sie Attribute 'Mitglieder innerhalb einer Methode

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

Im Main initialisiert ich das Mitglied Skip mit dem Wert true für das Verfahren foo().

Next ich die Funktion foo() nenne, die das Attribut [someAttribute()] und ich möchte überprüfen, ob das Mitglied Skip initialisiert wurde:

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

    return 1; 
} 

erhielt ich den Fehler "Der Name‚Weiter‘existiert nicht in der aktuelle Kontext ".
enter image description here

Wie kann ich die Mitglieder des Attributs innerhalb einer Methode überprüfen, die dieses Attribut verwendet?

Mein vollständiger Code:

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:
Ich habe BindingFlags.Static, um die refelction foo() die statische Funktion zu erhalten.

+0

Mögliches Duplikat [Reflection - erhalten Namen und Wert auf Eigenschaft Attribut] (http://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property) – HimBromBeere

+1

Ich nehme an, Sie werden 'BindingFlags.Static | BindingFlags.NonPublic' als 'foo'-Methode ist' private static'. – HimBromBeere

+0

Ich habe den Code bearbeitet und hinzugefügt, danke. – E235

Antwort

1

Sie das Attribut mit so etwas wie dies zu erreichen:

[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)); 
} 

in Ihrem initAttributes() Methode Wie auch immer, wenn Sie Assembly.GetExecutingAssembly().GetTypes().SelectMany tun, müssen Sie nicht die Methode foo bekommen, weil es static ist, so sollten Sie auch Verwenden Sie die BindingFlags.Static.

Auch you cannot set an attribute value at runtime, so dass die vorgenommenen Änderungen initAttributes werden nicht „gesehen“, wenn Sie das Attribut abgerufen werden (so Eigenschaft überspringen wird false)

+0

Upvoted für das Problem mit der Einstellung von Attributeigenschaften zur Laufzeit. Aber ich denke, die Stack-Trace-Ansatz kann fehlschlagen, wenn der Compiler eine Methode einreiht oder aufgrund anderer Optimierungen. –

1

Sie können mit Reflexion dieses Ziel erreichen:

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

    return 1; 
} 

Das die MethodInfo für foo und überprüft wird, ob das Verfahren die someAttribute hat. Wenn dies der Fall ist, wird die Skip Eigenschaft dieser Attributinstanz überprüft.

In Ihrem Fall benötigt GetMethod() noch einige Argumente, denn foo ist private und static. Wenn Sie mehrere Überlastungen von foo haben, werden Sie auch die Parametertypen angeben müssen:

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; 
} 

(Anmerkung: In einer früheren bearbeiten ich die ConditionalAttribute schlug stattdessen vor, aber offensichtlich ist dies nicht anwendbar auf nicht-Leere Methoden).

Verwandte Themen