¿Es posible consultar atributos personalizados en C # durante el tiempo de comstackción (no en tiempo de ejecución)?

En otras palabras, ¿podría ser posible crear un ensamblaje que ni siquiera se compile (suponiendo que el código de verificación no se elimine) si cada una de las Clases no tiene (“debe tener”) atributos personalizados (por ejemplo, Autor y Versión)?

Aquí está el código que he usado para consultar durante el tiempo de ejecución:

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 { } //} 

Edición: Sólo para justificar mi elección para la respuesta. Creo que CasperOne proporcionó la respuesta correcta de la pregunta.

Sin embargo, las razones para hacer la pregunta parecían ser débiles . Probablemente debería comenzar a usar alguna herramienta externa como: FinalBuilder o crear pruebas unitarias para verificar este “requisito”, usando Pex, Nunit u otros marcos de pruebas unitarias …

EDITAR Agregué un pequeño fragmento de código de un progtwig de consola al final de las respuestas que realiza la verificación … siéntase libre de comentar, criticar o sugerir mejoras
Una vez más, me di cuenta de que este “requisito” debería implementarse como parte de la prueba de la unidad justo antes del “check in”

No, no es posible enganchar en la comstackción del ensamblaje y verificar si existe.

Sin embargo , puede conectarse al proceso de comstackción, que se compone de algo más que ejecutar el comstackdor. Podría crear una tarea MSBUILD personalizada (o NAnt, si está usando eso) que verifica el ensamblaje a través de la reflexión después de que se construye y luego falla la comstackción si no tiene los atributos requeridos.

Por supuesto, probablemente deberías verificar esto también en el código. Lo que está intentando hacer no es un buen sustituto para un control de tiempo de ejecución adecuado.

Puede ejecutar un paso posterior a la comstackción que se refleje en la DLL para hacer lo que desea.

Tendrá que escribir una aplicación de línea de comandos que cargue la DLL y reflexione sobre los tipos. A continuación, ejecuta esa aplicación de línea de comandos como un paso posterior a la comstackción. He hecho esto en el pasado. No es terriblemente difícil hacerlo, suponiendo que entiendas la API de reflexión.

PostSharp hace esto para lograr una progtwigción orientada a aspectos. Muy bien, en realidad.

Los atributos son tiempo de ejecución solamente. Sin embargo :

Sería posible crear una regla en FXCop (análisis estático) que falle si el atributo no está definido, y su proceso de creación / registro podría verificar esa regla y fallar adecuadamente.

No conozco ninguna forma de conectarse al proceso de comstackción de C #, pero puede adoptar un enfoque diferente y crear una herramienta personalizada lanzada en el evento posterior a la comstackción que podría cargar su ensamblaje y reflexionar sobre eso. Dependiendo de lo que devuelva la herramienta, todo el proceso de comstackción resultará en un éxito o una falla, por lo que puede devolver un error con su herramienta y hacer que la comstackción falle, al tiempo que proporciona más detalles sobre la escritura de fallas en la consola.

Para mí, esto parece más un problema de prueba que un problema de comstackción. Es decir, estás preguntando “¿cómo sé que mi código está escrito correctamente?” donde “escrito correctamente” tiene (entre otras cosas) la connotación de que todas las clases están decoradas con un atributo particular. Consideraría escribir pruebas unitarias que verifiquen que, de hecho, se siguen las reglas de inclusión de sus atributos. Puede hacer que su proceso de comstackción (y / o registro) ejecute este conjunto particular de pruebas después de la construcción (antes del registro) como condición para una construcción exitosa (registro). No romperá la comstackción, ya que debe completarse para que se ejecuten las pruebas, pero romperá la comstackción, por así decirlo.

 //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 espacio de nombres