Ist es möglich, benutzerdefinierte Attribute in C # während der Kompilierung (nicht Laufzeit) abfragen

StackOverflow https://stackoverflow.com/questions/753255

  •  09-09-2019
  •  | 
  •  

Frage

Mit anderen Worten könnte es möglich sein, Assembly zu erstellen, die nicht kompiliert auch (unter der Annahme des Überprüfungscode nicht entfernt wird), wenn jede der Klassen hat nicht ( „must have“) benutzerdefinierte Attribute (zB Autor und Version)?

Hier ist der Code, den ich für die Abfrage während der Laufzeit verwendet haben:

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


namespace ForceMetaAttributes
{

    [System.AttributeUsage ( System.AttributeTargets.Method, AllowMultiple = true )]
    class TodoAttribute : System.Attribute
    {
        public TodoAttribute ( string message )
        {
            Message = message;
        }
        public readonly string Message;

    }

    [System.AttributeUsage ( System.AttributeTargets.Class |
        System.AttributeTargets.Struct, AllowMultiple = true )]
    public class AttributeClass : System.Attribute
    {
        public string Description { get; set; }
        public string MusHaveVersion { get; set; }


        public AttributeClass ( string description, string mustHaveVersion ) 
        {
            Description = description; 
            MusHaveVersion = mustHaveVersion ; 
        }

    } //eof class 


    [AttributeClass("AuthorName" , "1.0.0")]
    class ClassToDescribe
    {
        [Todo ( " A todo message " )]
        static void Method ()
        { }
    } //eof class 

    //how to get this one to fail on compile 
    class AnotherClassToDescribe
    { 

    } //eof class 

class QueryApp
{
        public static void Main()
        {

                Type type = typeof(ClassToDescribe);
                AttributeClass objAttributeClass;


                //Querying Class Attributes

                foreach (Attribute attr in type.GetCustomAttributes(true))
                {
                        objAttributeClass = attr as AttributeClass;
                        if (null != objAttributeClass)
                        {
                                Console.WriteLine("Description of AnyClass:\n{0}", 
                                                                    objAttributeClass.Description);
                        }
                }



                //Querying Class-Method Attributes  

                foreach(MethodInfo method in type.GetMethods())
                {
                        foreach (Attribute attr in method.GetCustomAttributes(true))
                        {
                                objAttributeClass = attr as AttributeClass;
                                if (null != objAttributeClass)
                                {
                                        Console.WriteLine("Description of {0}:\n{1}", 
                                                                            method.Name, 
                                                                            objAttributeClass.Description);
                                }
                        }
                }
                //Querying Class-Field (only public) Attributes

                foreach(FieldInfo field in type.GetFields())
                {
                        foreach (Attribute attr in field.GetCustomAttributes(true))
                        {
                                objAttributeClass= attr as AttributeClass;
                                if (null != objAttributeClass)
                                {
                                        Console.WriteLine("Description of {0}:\n{1}",
                                                                            field.Name,objAttributeClass.Description);
                                }
                        }
                }
                Console.WriteLine ( "hit Enter to exit " );
                Console.ReadLine ();
        } //eof Main 
} //eof class 

} //eof namespace 


//uncomment to check whether it works with external namespace 
//namespace TestNamespace {

//  class Class1 { }
//  class Class2 { }

//}

Edit: Nur meine Wahl zu rechtfertigen, für Antwort. Ich denke, casperOne die richtige Antwort auf die Frage zur Verfügung gestellt.

Allerdings sind die Gründe für die Frage zu stellen schien schwach . Wahrscheinlich soll ich beginnen, einige externen Tools zu verwenden, wie zum Beispiel: Finalbuilder oder Unit-Tests schaffen für diese "Anforderung" Überprüfung, mit Pex, Nunit oder einem anderen Einheit Test-Frameworks ...

Bearbeiten Ich habe eine kleine Code-Schnipsel am Ende eines Konsolenprogramm der Antworten, die die Kontrolle ... fühlen Sie sich frei zu äußern, Kritik oder Verbesserungsvorschläge führt
Noch einmal wurde mir klar, dass diese „Anforderung“ als Teil der Unit-Tests durchgeführt werden, kurz bevor die „Check-in“

War es hilfreich?

Lösung

Nein, es ist nicht möglich, in die Zusammenstellung der Baugruppe zu anschließen und prüfen, ob es vorhanden ist.

Jedoch können Sie in den Build-Prozess anschließen, die aus mehr als nur laufen, die Compiler gemacht wird. Sie könnten eine benutzerdefinierte MSBUILD Aufgabe (oder NAnt, wenn Sie das verwenden) erstellen, die die Anordnung durch Reflexion überprüft, nachdem es gebaut wird und dann das Build fehl, wenn es nicht die erforderlichen Eigenschaften hat.

Natürlich sollten Sie wahrscheinlich noch dies auch im Code überprüfen. Was Sie versuchen, ist kein guter Ersatz für eine richtige Laufzeitprüfung zu tun.

Andere Tipps

Sie können einen Post-Build-Schritt ausführen, die auf dem DLL reflektiert zu tun, was Sie wollen.

In Kürze erhalten Sie eine Befehlszeile app schreiben, die die DLL lädt und reflektiert über die Arten. Sie führen dann die Befehlszeile app als Post-Build-Schritt. Ich habe dies in der Vergangenheit getan. Es ist nicht sehr schwer zu tun, vorausgesetzt, Sie das Reflection-API verstehen.

Postsharp hat dieser Aspekt orientierte Programmierung zu erreichen. Ziemlich cool, eigentlich.

Attribute werden nur die Laufzeit. Allerdings:

Es wäre möglich, eine Regel in FXCop (statische Analyse) zu erstellen, die fehlschlägt, wenn das Attribut nicht definiert ist, und Ihr Build / checkin Prozess die Regel überprüfen könnte, und nicht angemessen.

Ich bin mir nicht bewusst irgendeine Weise in die C # Kompilierungsvorgang einzuhaken, aber Sie können einen anderen Ansatz nehmen und ein eigenes Werkzeug auf dem Postbuildereignis gestartet schaffen, die die Assembly geladen werden konnten und reflektiert das. Je nachdem, was das Werkzeug liefert den gesamten Build-Prozess in einem Erfolg oder einem Ausfall führen, so können Sie nur einen Fehler mit Ihrem Tool zurückzukehren und den Build machen scheitern, während weitere Informationen über den Fehler schriftlich offen zu trösten.

Für mich scheint eher wie ein Testproblem als ein Kompilierung Problem. Das heißt, Sie fragen: „Wie kann ich wissen, dass mein Code richtig geschrieben?“ wobei „richtig geschrieben“ hat (unter anderem) die Konnotation, dass alle Klassen mit einem bestimmten Attribut versehen sind. Ich halte würde Unit-Tests schreiben, die sicherstellen, dass Ihre Attribut Inklusion Regeln sind in der Tat gefolgt. Sie hätten Ihren Build (und / oder checkin) Verfahren zur Herstellung dieses speziellen Satz von Tests nach dem Build-Lauf (vor dem Check) als Bedingung für einen erfolgreichen Build (checkin). Es wird nicht die Kompilierung brechen, denn das ist für die Tests, um zu vollenden muss laufen, aber es wird die Build brechen, so zu sprechen.

//PLEASE COMMENT IF YOU FIND BUGS OR SUGGEST IMPROVEMENTS


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

namespace MustHaveAttributes
{
 [AttributeClass ( "Yordan Georgiev", "1.0.0" )] 
 class Program
 {


 static void Main ( string [] args )
 {
  bool flagFoundCustomAttrOfTypeAttributeClass = false; 
  Console.WriteLine ( " START " );

  // what is in the assembly
  Assembly a = Assembly.Load ( "MustHaveAttributes" );
  Type[] types = a.GetTypes ();
  foreach (Type t in types)
  {
   object[] arrCustomAttributes = t.GetCustomAttributes ( true );


   if (arrCustomAttributes == null || arrCustomAttributes.GetLength ( 0 ) == 0)
   {
    //DO NOT CHECK IN
    ExitProgram ( t, "Found class without CustomAttributes" );
   }


   foreach (object objCustomAttribute in arrCustomAttributes)
   {
    Console.WriteLine ( "CustomAttribute for type  is {0}", t );
    if (objCustomAttribute is AttributeClass)
     flagFoundCustomAttrOfTypeAttributeClass = true; 
   }

   if (flagFoundCustomAttrOfTypeAttributeClass == false)
   { //DO NOT CHECK IN 
    ExitProgram ( t, "Did not found custom attribute of type AttributeClass" );
   }
   Console.WriteLine ( "Type is {0}", t );
  }
  Console.WriteLine ("{0} types found", types.Length );

  //NOW REQUIREMENTS IS PASSED CHECK IN
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();
  Console.WriteLine ( " END " );
 }



 static void ExitProgram ( Type t, string strExitMsg  )
 {

  Console.WriteLine ( strExitMsg );
  Console.WriteLine ( "Type is {0}", t );
  Console.WriteLine ( " HIT A KEY TO EXIT " );
  Console.ReadLine ();

  System.Environment.Exit ( 1 );

 }
} //eof Program


//This will fail even to compile since the constructor requires two params
//[AttributeClass("OnlyAuthor")]  
//class ClassOne
//{ 

//} //eof class 


////this will not check in since this class does not have required custom
////attribute
//class ClassWithoutAttrbute
//{ }



[AttributeClass("another author name " , "another version")]
class ClassTwo
{ 

} //eof class


[System.AttributeUsage ( System.AttributeTargets.Class |
 System.AttributeTargets.Struct, AllowMultiple = true )]
public class AttributeClass : System.Attribute
{

 public string MustHaveDescription { get; set; }
 public string MusHaveVersion { get; set; }


 public AttributeClass ( string mustHaveDescription, string mustHaveVersion )
 {
  MustHaveDescription = mustHaveDescription;
  MusHaveVersion = mustHaveVersion;
 }

} //eof class 

} // EOF-Namespace

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top