Atributos más útiles

Sé que los atributos son extremadamente útiles. Hay algunos predefinidos como [Browsable(false)] que le permite ocultar propiedades en la pestaña de propiedades. Aquí hay una buena pregunta que explica los atributos: ¿Cuáles son los atributos en .NET?

¿Cuáles son los atributos predefinidos (y su espacio de nombres) que realmente usa en sus proyectos?

[DebuggerDisplay] puede ser realmente útil para ver rápidamente el resultado personalizado de un Tipo cuando pasa el mouse sobre la instancia del Tipo durante la depuración. ejemplo:

 [DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")] class Customer { public string FirstName; public string LastName; } 

Así es como debería verse en el depurador:

texto alternativo http://sofes.miximages.com/c%23/temp.jpg

Además, vale la pena mencionar que el atributo [WebMethod] con el CacheDuration propiedades CacheDuration puede evitar la ejecución innecesaria del método del servicio web.

System.Obsolete es uno de los atributos más útiles en el marco, en mi opinión. La capacidad de generar una advertencia sobre el código que ya no se debe usar es muy útil. Me encanta contar con una forma de decirles a los desarrolladores que algo no se debe usar más, así como tener una manera de explicar por qué y señalar la mejor / nueva forma de hacer algo.

El Conditional attribute es muy útil para el uso de depuración. Le permite agregar métodos en su código con fines de depuración que no se comstackrán cuando genere su solución para su lanzamiento.

Luego, hay muchos atributos específicos de Web Controls que considero útiles, pero son más específicos y no tienen ningún uso fuera del desarrollo de los controles del servidor de los que he encontrado.

[Flags] es bastante útil. Azúcar sintáctico para estar seguro, pero aún bastante agradable.

 [Flags] enum SandwichStuff { Cheese = 1, Pickles = 2, Chips = 4, Ham = 8, Eggs = 16, PeanutButter = 32, Jam = 64 }; public Sandwich MakeSandwich(SandwichStuff stuff) { Console.WriteLine(stuff.ToString()); // ... } // ... MakeSandwich(SandwichStuff.Cheese | SandwichStuff.Ham | SandwichStuff.PeanutButter); // produces console output: "Cheese, Ham, PeanutButter" 

Leppie señala algo de lo que no me había dado cuenta, y que más bien amortigua mi entusiasmo por este atributo: no ordena al comstackdor que permita combinaciones de bits como valores válidos para variables de enumeración, el comstackdor lo permite para enumeraciones independientemente. Mi fondo de C ++ se muestra a través de … suspiro

Me gusta [DebuggerStepThrough] de System.Diagnostics .

Es muy útil para evitar entrar en esos métodos o propiedades de una línea sin nada (si se ve obligado a trabajar en una .Net temprana sin propiedades automáticas). Coloque el atributo en un método breve o en el captador o instalador de una propiedad, y volará directamente incluso cuando presione “entrar” en el depurador.

Por lo que vale, aquí hay una lista de todos los atributos de .NET . Hay varios cientos.

¡No sé de nadie más pero tengo algunos RTFM serios para hacer!

Mi voto sería para [Conditional]

 [Conditional("DEBUG")] public void DebugOnlyFunction() { // your code here } 

Puede usar esto para agregar una función con funciones avanzadas de depuración; como Debug.Write , solo se llama en comstackciones de depuración, y por lo tanto le permite encapsular lógica compleja de depuración fuera del flujo principal de su progtwig.

Siempre uso los atributos DefaultValue , Description y DefaultValue sobre las propiedades públicas de mis controles de usuario, controles personalizados o cualquier clase que edite a través de una grilla de propiedades. Estas tags son utilizadas por .NET PropertyGrid para formatear el nombre, el panel de descripción y los valores en negrita que no están configurados en los valores predeterminados.

 [DisplayName("Error color")] [Description("The color used on nodes containing errors.")] [DefaultValue(Color.Red)] public Color ErrorColor { ... } 

Solo desearía que el IntelliSense de Visual Studio tuviera en cuenta el atributo Description si no se encuentran comentarios XML. Evitaría tener que repetir la misma oración dos veces.

[Serializable] se usa todo el tiempo para serializar y deserializar objetos hacia y desde fonts de datos externas como xml o desde un servidor remoto. Más sobre esto aquí.

En el espíritu de Hofstadt, el [Attribute] es muy útil, ya que es la forma en que creas tus propios atributos. Utilicé atributos en lugar de interfaces para implementar sistemas de complementos, agregar descripciones a Enums, simular envíos múltiples y otros trucos.

He encontrado que [DefaultValue] es bastante útil.

Aquí está la publicación sobre el interesante atributo InternalsVisibleTo . Básicamente, lo que hace imita la funcionalidad de acceso de los amigos de C ++. Resulta muy útil para las pruebas unitarias.

Sugeriría [TestFixture] y [Test] – de la biblioteca nUnit .

Las pruebas unitarias en su código brindan seguridad en la refactorización y la documentación codificada.

 [XmlIgnore] 

ya que esto le permite ignorar (en cualquier serialización xml) objetos ‘padre’ que de lo contrario causarían excepciones al guardar.

No está bien nombrado, no está bien soportado en el marco, y no debería requerir un parámetro, pero este atributo es un marcador útil para las clases inmutables:

 [ImmutableObject(true)] 

Me gusta utilizar el atributo [ThreadStatic] en combinación con el hilo y la progtwigción basada en la stack. Por ejemplo, si quiero un valor que deseo compartir con el rest de una secuencia de llamadas, pero quiero hacerlo fuera de banda (es decir, fuera de los parámetros de llamada), podría emplear algo como esto.

 class MyContextInformation : IDisposable { [ThreadStatic] private static MyContextInformation current; public static MyContextInformation Current { get { return current; } } private MyContextInformation previous; public MyContextInformation(Object myData) { this.myData = myData; previous = current; current = this; } public void Dispose() { current = previous; } } 

Más adelante en mi código, puedo usar esto para proporcionar información contextual fuera de banda a las personas que se encuentran aguas abajo de mi código. Ejemplo:

 using(new MyContextInformation(someInfoInContext)) { ... } 

El atributo ThreadStatic me permite enfocar la llamada solo al hilo en cuestión, evitando el problemático problema del acceso a los datos a través de los hilos.

DesignerSerializationVisibilityAttribute es muy útil. Cuando coloca una propiedad de tiempo de ejecución en un control o componente y no desea que el diseñador la serialice, la usa así:

 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Foo Bar { get { return baz; } set { baz = value; } } 

El DebuggerHiddenAttribute que permite evitar el paso al código que no debe ser depurado.

 public static class CustomDebug { [DebuggerHidden] public static void Assert(Boolean condition, Func exceptionCreator) { ... } } ... // The following assert fails, and because of the attribute the exception is shown at this line // Isn't affecting the stack trace CustomDebug.Assert(false, () => new Exception()); 

También evita que se muestren métodos en el seguimiento de stack, útil cuando se tiene un método que simplemente ajusta otro método:

 [DebuggerHidden] public Element GetElementAt(Vector2 position) { return GetElementAt(position.X, position.Y); } public Element GetElementAt(Single x, Single y) { ... } 

Si ahora llama a GetElementAt(new Vector2(10, 10)) y se produce un error en el método envuelto, la stack de llamadas no muestra el método que llama al método que arroja el error.

Solo unos pocos atributos obtienen soporte del comstackdor, pero un uso muy interesante de los atributos es en AOP: PostSharp usa sus atributos personalizados para inyectar IL en métodos, permitiendo todo tipo de habilidades … log / trace son ejemplos triviales, pero algunos otros buenos ejemplos son cosas como la implementación automática INotifyPropertyChanged ( aquí ).

Algunos que ocurren e impactan directamente en el comstackdor o en el tiempo de ejecución :

  • [Conditional("FOO")] : las llamadas a este método (incluida la evaluación de argumentos) solo se producen si el símbolo “FOO” se define durante la comstackción
  • [MethodImpl(...)] : se usa para indicar algunas cosas como la sincronización, en línea
  • [PrincipalPermission(...)] – se usa para inyectar verificaciones de seguridad en el código automáticamente
  • [TypeForwardedTo(...)] : se usa para mover tipos entre ensamblajes sin reconstruir las llamadas

Para cosas que se comprueban manualmente a través de la reflexión, soy un gran admirador de los atributos System.ComponentModel ; cosas como [TypeDescriptionProvider(...)] , [TypeConverter(...)] y [Editor(...)] que pueden cambiar por completo el comportamiento de los tipos en escenarios de enlace de datos (es decir, propiedades dinámicas, etc.).

He estado usando el [DataObjectMethod] últimamente. Describe el método para que pueda usar su clase con ObjectDataSource (u otros controles).

 [DataObjectMethod(DataObjectMethodType.Select)] [DataObjectMethod(DataObjectMethodType.Delete)] [DataObjectMethod(DataObjectMethodType.Update)] [DataObjectMethod(DataObjectMethodType.Insert)] 

Más información

Si tuviera que hacer un rastreo de cobertura de código, creo que estos dos serían los mejores:

  [Serializable] [WebMethod] 

En nuestro proyecto actual, usamos

 [ComVisible(false)] 

Controla el acceso de un tipo o miembro administrado individual, o de todos los tipos dentro de un ensamblaje, a COM.

Más información

 [TypeConverter(typeof(ExpandableObjectConverter))] 

Le dice al diseñador que expanda las propiedades que son clases (de su control)

 [Obfuscation] 

Indica a las herramientas de ofuscación que realicen las acciones especificadas para un ensamblaje, tipo o miembro. (Aunque normalmente utiliza un nivel de [assembly:ObfuscateAssemblyAttribute(true)]

Los atributos que uso más son los relacionados con la serialización XML.

XmlRoot

XmlElement

XmlAttribute

etc …

Extremadamente útil cuando se hace un análisis XML o serialización rápido y sucio.

Siendo un desarrollador de nivel medio me gusta

System.ComponentModel.EditorBrowsableAttribute Me permite ocultar propiedades para que el desarrollador de UI no se vea abrumado con propiedades que no necesita ver.

System.ComponentModel.BindableAttribute Algunas cosas no necesitan ser databound. Nuevamente, disminuye el trabajo que los desarrolladores de UI deben hacer.

También me gusta el DefaultValue que mencionó Lawrence Johnston.

System.ComponentModel.BrowsableAttribute y los Flags se utilizan con regularidad.

Yo uso System.STAThreadAttribute System.ThreadStaticAttribute cuando sea necesario.

Por cierto. Estos son tan valiosos para todos los desarrolladores de .Net framework.

[EditorBrowsable(EditorBrowsableState.Never)] permite ocultar propiedades y métodos de IntelliSense si el proyecto no está en su solución. Muy útil para ocultar flujos no válidos para interfaces fluidas. ¿Con qué frecuencia desea GetHashCode () o Equals ()?

Para MVC [ActionName("Name")] permite tener una acción Obtener y Publicar acción con la misma firma de método, o para usar guiones en el nombre de la acción, que de otro modo no sería posible sin crear una ruta para ello.

En la parte superior de mi cabeza, aquí hay una lista rápida, aproximadamente ordenada por frecuencia de uso, de los atributos predefinidos que realmente uso en un gran proyecto (~ 500k LoCs):

Banderas, Serializable, WebMethod, COMVisible, TypeConverter, Conditional, ThreadStatic, Obsolete, InternalsVisibleTo, DebuggerStepThrough.

[DeploymentItem("myFile1.txt")] MSDN Doc en DeploymentItem

Esto es realmente útil si está probando un archivo o usando el archivo como entrada para su prueba.

Genero clase de entidad de datos a través de CodeSmith y uso atributos para alguna rutina de validación. Aquí hay un ejemplo:

 ///  /// Firm ID ///  [ChineseDescription("送样单位编号")] [ValidRequired()] public string FirmGUID { get { return _firmGUID; } set { _firmGUID = value; } } 

Y obtuve una clase de utilidad para hacer la validación en función de los atributos asociados a la clase de entidad de datos. Aquí está el código:

 namespace Reform.Water.Business.Common { ///  /// Validation Utility ///  public static class ValidationUtility { ///  /// Data entity validation ///  /// Data entity object /// return true if the object is valid, otherwise return false public static bool Validate(object data) { bool result = true; PropertyInfo[] properties = data.GetType().GetProperties(); foreach (PropertyInfo p in properties) { //Length validatioin Attribute attribute = Attribute.GetCustomAttribute(p,typeof(ValidLengthAttribute), false); if (attribute != null) { ValidLengthAttribute validLengthAttribute = attribute as ValidLengthAttribute; if (validLengthAttribute != null) { int maxLength = validLengthAttribute.MaxLength; int minLength = validLengthAttribute.MinLength; string stringValue = p.GetValue(data, null).ToString(); if (stringValue.Length < minLength || stringValue.Length > maxLength) { return false; } } } //Range validation attribute = Attribute.GetCustomAttribute(p,typeof(ValidRangeAttribute), false); if (attribute != null) { ValidRangeAttribute validRangeAttribute = attribute as ValidRangeAttribute; if (validRangeAttribute != null) { decimal maxValue = decimal.MaxValue; decimal minValue = decimal.MinValue; decimal.TryParse(validRangeAttribute.MaxValueString, out maxValue); decimal.TryParse(validRangeAttribute.MinValueString, out minValue); decimal decimalValue = 0; decimal.TryParse(p.GetValue(data, null).ToString(), out decimalValue); if (decimalValue < minValue || decimalValue > maxValue) { return false; } } } //Regex validation attribute = Attribute.GetCustomAttribute(p,typeof(ValidRegExAttribute), false); if (attribute != null) { ValidRegExAttribute validRegExAttribute = attribute as ValidRegExAttribute; if (validRegExAttribute != null) { string objectStringValue = p.GetValue(data, null).ToString(); string regExString = validRegExAttribute.RegExString; Regex regEx = new Regex(regExString); if (regEx.Match(objectStringValue) == null) { return false; } } } //Required field validation attribute = Attribute.GetCustomAttribute(p,typeof(ValidRequiredAttribute), false); if (attribute != null) { ValidRequiredAttribute validRequiredAttribute = attribute as ValidRequiredAttribute; if (validRequiredAttribute != null) { object requiredPropertyValue = p.GetValue(data, null); if (requiredPropertyValue == null || string.IsNullOrEmpty(requiredPropertyValue.ToString())) { return false; } } } } return result; } } } 

Considero que es importante mencionar aquí que los siguientes atributos también son muy importantes:

 STAThreadAttribute 

Indica que el modelo de subprocesamiento COM para una aplicación es apartamento de subproceso único (STA).

Por ejemplo, este atributo se usa en las aplicaciones de Windows Forms:

 static class Program { ///  /// The main entry point for the application. ///  [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } 

Y también …

 SuppressMessageAttribute 

Suprime el informe de una violación de regla de herramienta de análisis estático específica, lo que permite supresiones múltiples en un artefacto de código único.

Por ejemplo:

 [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "isChecked")] [SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "fileIdentifier")] static void FileNode(string name, bool isChecked) { string fileIdentifier = name; string fileName = name; string version = String.Empty; } 

[System.Security.Permissions.PermissionSetAttribute] permite que las acciones de seguridad para un PermissionSet se apliquen al código utilizando seguridad declarativa.

 // usage: public class FullConditionUITypeEditor : UITypeEditor { // The immediate caller is required to have been granted the FullTrust permission. [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")] public FullConditionUITypeEditor() { } }