c# - example - Atributos más útiles
remarks c# (30)
Sé que los atributos son extremadamente útiles. Existen 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: ¿Qué son los atributos en .NET?
¿Cuáles son los atributos predefinidos (y su espacio de nombres) que realmente utiliza en sus proyectos?
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 un apartamento de un solo subproceso (STA).
Por ejemplo, este atributo se usa en las aplicaciones de Windows Forms:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
Y también ...
SuppressMessageAttribute
Suprime la notificación de una infracción específica de la regla de la herramienta de análisis estático, lo que permite múltiples supresiones en un solo artefacto de código.
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;
}
En el espíritu de Hofstadt, el [Attribute]
es muy útil, ya que es cómo se crean sus propios atributos. He usado atributos en lugar de interfaces para implementar sistemas de complementos, agregar descripciones a Enums, simular múltiples despachos y otros trucos.
En la parte superior de mi cabeza, aquí hay una lista rápida, ordenada aproximadamente por la frecuencia de uso, de los atributos predefinidos que realmente uso en un gran proyecto (~ 500k LoC):
Flags, Serializable, WebMethod, COMVisible, TypeConverter, Conditional, ThreadStatic, Obsolete, InternalsVisibleTo, DebuggerStepThrough.
En nuestro proyecto actual, utilizamos
[ComVisible(false)]
Controla la accesibilidad de un tipo o miembro administrado individual, o de todos los tipos dentro de un ensamblaje, a COM.
Genero clase de entidad de datos a través de CodeSmith y uso atributos para alguna rutina de validación. Aquí hay un ejemplo:
/// <summary>
/// Firm ID
/// </summary>
[ChineseDescription("送样单位编号")]
[ValidRequired()]
public string FirmGUID
{
get { return _firmGUID; }
set { _firmGUID = value; }
}
Y obtuve una clase de utilidad para realizar la validación basada en los atributos adjuntos a la clase de entidad de datos. Aquí está el código:
namespace Reform.Water.Business.Common
{
/// <summary>
/// Validation Utility
/// </summary>
public static class ValidationUtility
{
/// <summary>
/// Data entity validation
/// </summary>
/// <param name="data">Data entity object</param>
/// <returns>return true if the object is valid, otherwise return false</returns>
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;
}
}
}
He encontrado que [DefaultValue]
es bastante útil.
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)]
Los atributos que más utilizo son los relacionados con la serialización XML.
XmlRoot
XmlElement
XmlAttribute
etc ...
Extremadamente útil cuando se realiza cualquier análisis o serialización XML rápido y sucio.
Me gusta [DebuggerStepThrough]
de System.Diagnostics .
Es muy útil para evitar entrar en esos métodos o propiedades de no hacer nada de una línea (si se ve obligado a trabajar en una .Net temprana sin propiedades automáticas). Ponga el atributo en un método corto o en el que obtiene o establece una propiedad, y volará hacia la derecha incluso cuando presione "entrar en" en el depurador.
Me gusta usar el atributo [ThreadStatic]
en combinación con programación basada en hilos y en la pila. Por ejemplo, si quiero un valor que quiero compartir con el resto 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 la banda a las personas que están más abajo de mi código. Ejemplo:
using(new MyContextInformation(someInfoInContext)) {
...
}
El atributo ThreadStatic me permite ubicar la llamada solo en el hilo en cuestión, evitando el desordenado problema del acceso a los datos a través de los hilos.
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; al igual que Debug.Write
, solo se Debug.Write
en compilaciones de depuración, por lo que le permite encapsular lógica de depuración compleja fuera del flujo principal de su programa.
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 clases inmutables:
[ImmutableObject(true)]
Para lo que vale, aquí hay una lista de todos los atributos .NET . Hay varios cientos.
No conozco a nadie más, ¡pero tengo que hacer un RTFM serio!
Ser un desarrollador de nivel medio que me gusta
System.ComponentModel.EditorBrowsableAttribute
Me permite ocultar propiedades para que el desarrollador de IU no se vea abrumado por las propiedades que no necesitan ver.
System.ComponentModel.BindableAttribute
Algunas cosas no necesitan estar vinculadas a datos. Nuevamente, disminuye el trabajo que los desarrolladores de IU deben hacer.
También me gusta el DefaultValue
que mencionó Lawrence Johnston.
System.ComponentModel.BrowsableAttribute
y los Flags
se utilizan regularmente.
Yo uso System.STAThreadAttribute System.ThreadStaticAttribute
cuando sea necesario.
Por cierto. Estos son tan valiosos para todos los desarrolladores de .Net framework.
Si tuviera que hacer un rastreo de cobertura de código, creo que estos dos serían los mejores:
[Serializable]
[WebMethod]
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 cuadrícula de propiedades. Estas propiedades son utilizadas por .NET PropertyGrid para formatear el nombre, el panel de descripción y los valores en negrita que no están establecidos en los valores predeterminados.
[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
...
}
Solo deseo que el IntelliSense de Visual Studio tenga en cuenta el atributo Description
si no se encuentra ningún comentario XML. Evitaría tener que repetir la misma frase dos veces.
Solo unos pocos atributos obtienen soporte del compilador, pero un uso muy interesante de los atributos está en AOP: PostSharp usa sus atributos a medida para inyectar IL en los 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 de INotifyPropertyChanged ( here ).
Algunos que ocurren e impactan el compilador o el tiempo de ejecución directamente :
-
[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 compilación -
[MethodImpl(...)]
: se utiliza para indicar algunas cosas como sincronización, alineación -
[PrincipalPermission(...)]
: se utiliza para inyectar controles de seguridad en el código automáticamente -
[TypeForwardedTo(...)]
: se usa para mover tipos entre ensamblajes sin reconstruir los llamadores
Para las cosas que se verifican manualmente a través de la reflexión: soy un gran fan de los atributos System.ComponentModel
; cosas como [TypeDescriptionProvider(...)]
, [TypeConverter(...)]
, y [Editor(...)]
que pueden cambiar completamente el comportamiento de los tipos en escenarios de enlace de datos (es decir, propiedades dinámicas, etc.).
Sugeriría [TestFixture]
y [Test]
- de la biblioteca nUnit .
Las pruebas unitarias en su código proporcionan seguridad en la refactorización y la documentación codificada.
Here está el post sobre el interesante atributo InternalsVisibleTo . Básicamente, lo que hace imita la funcionalidad de acceso de los amigos de C ++. Es muy útil para la prueba de la unidad.
DesignerSerializationVisibilityAttribute
es muy útil. Cuando pones una propiedad de tiempo de ejecución en un control o componente, y no quieres que el diseñador la serialice, la usas así:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
get { return baz; }
set { baz = value; }
}
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<Exception> 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 mostrar métodos en el seguimiento de la pila, útil cuando se tiene un método que simplemente envuelve 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 ocurre un error en el método envuelto, la pila de llamadas no muestra el método que está llamando al método que lanza el error.
[Flags]
es bastante útil. Azúcar sintáctica para estar seguro, pero todavía 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 frena mi entusiasmo por este atributo: no indica al compilador que permita combinaciones de bits como valores válidos para las variables de enumeración, aunque el compilador permite esto para las enumeraciones. Mi fondo de C ++ se muestra a través de ... suspiro
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 tener una forma de decirle a los desarrolladores que ya no se debe usar algo, así como 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 para propósitos de depuración que no se compilarán cuando compile su solución para el lanzamiento.
Luego hay una gran cantidad de atributos específicos de los Controles Web que me parecen útiles, pero son más específicos y no tienen ningún uso fuera del desarrollo de los controles del servidor de lo que he encontrado.
[DebuggerDisplay]
puede ser realmente útil para ver rápidamente la salida personalizada de un Tipo cuando pasas 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://serialize.wordpress.com/files/2008/10/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 de servicio web.
[DeploymentItem("myFile1.txt")]
MSDN Doc en DeploymentItem
Esto es realmente útil si está probando contra un archivo o utilizando el archivo como entrada para su prueba.
[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 Get y una acción Post con la misma firma de método, o usar guiones en el nombre de la acción, que de otro modo no sería posible sin crear una ruta para ello.
[Serializable]
se usa todo el tiempo para serializar y deserializar objetos hacia y desde fuentes de datos externas, como xml o desde un servidor remoto. Más sobre esto aquí.
[System.Security.Permissions.PermissionSetAttribute]
permite que las acciones de seguridad para un PermissionSet se apliquen al código usando 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() { }
}
[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 se usa un nivel de [assembly:ObfuscateAssemblyAttribute(true)]
[XmlIgnore]
ya que esto le permite ignorar (en cualquier serialización xml) los objetos ''primarios'' que de lo contrario causarían excepciones al guardar.