Je sais que les attributs sont extrêmement utiles. Il en existe certains prédéfinis, tels que [Browsable(false)]
, qui vous permet de masquer des propriétés dans l'onglet Propriétés. Voici une bonne question expliquant les attributs: Que sont les attributs dans .NET?
Quels sont les attributs prédéfinis (et leur espace de noms) que vous utilisez réellement dans vos projets?
[DebuggerDisplay]
peut être très utile pour voir rapidement la sortie personnalisée d'un Type lorsque vous passez la souris sur son instance pendant le débogage. exemple:
[DebuggerDisplay("FirstName={FirstName}, LastName={LastName}")]
class Customer
{
public string FirstName;
public string LastName;
}
Voici comment cela devrait apparaître dans le débogueur:
De plus, il est à noter que l'attribut [WebMethod]
avec la propriété CacheDuration
peut éviter l'exécution inutile de la méthode de service Web.
System.Obsolete
est l'un des attributs les plus utiles du cadre, à mon avis. La possibilité de générer un avertissement sur le code qui ne devrait plus être utilisé est très utile. J'aime avoir un moyen de dire aux développeurs que quelque chose ne devrait plus être utilisé, ainsi qu'un moyen d'expliquer pourquoi et d'indiquer la meilleure/nouvelle façon de faire quelque chose.
Le Conditional attribute
est également très pratique pour l'utilisation du débogage. Il vous permet d'ajouter des méthodes dans votre code à des fins de débogage qui ne seront pas compilées lors de la génération de votre solution.
Ensuite, il y a beaucoup d'attributs spécifiques aux contrôles Web que je trouve utiles, mais ceux-ci sont plus spécifiques et n'ont aucune utilisation en dehors du développement des contrôles serveur à partir de ce que j'ai trouvé.
[Flags]
est très pratique. Sucre syntaxique certes, mais quand même plutôt gentil.
_[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 indique quelque chose que je n'avais pas compris et qui freine plutôt mon enthousiasme pour cet attribut: il ne le fait pas indique au compilateur d'autoriser les combinaisons de bits en tant que valeurs valides pour les variables d'énumération, ce que le compilateur autorise également pour les énumérations. Mon fond C++ apparaissant à travers ... soupir
J'aime [DebuggerStepThrough]
de System.Diagnostics .
C'est très pratique pour éviter d'entrer dans ces méthodes ou propriétés d'une seule ligne (si vous êtes obligé de travailler dans un ancien .Net sans propriétés automatiques). Placez l'attribut sur une méthode courte ou sur le getter ou le setter d'une propriété et vous survolerez même lorsque vous appuierez sur "step into" dans le débogueur.
Pour ce que ça vaut, voici ne liste de tous les attributs .NET . Il y en a plusieurs centaines.
Je ne connais personne d'autre, mais j'ai du mal à faire RTFM!
Mon vote serait pour [Conditional]
[Conditional("DEBUG")]
public void DebugOnlyFunction()
{
// your code here
}
Vous pouvez l'utiliser pour ajouter une fonction avec des fonctionnalités de débogage avancées. comme Debug.Write
, il est appelé uniquement dans les versions de débogage et vous permet donc d'encapsuler une logique de débogage complexe en dehors du flux principal de votre programme.
J'utilise toujours les attributs DisplayName
, Description
et DefaultValue
sur les propriétés publiques de mes contrôles utilisateur, contrôles personnalisés ou toute classe que je modifierai via une grille de propriétés. .NET PropertyGrid utilise ces balises pour formater le nom, le panneau de description et les valeurs en gras qui ne sont pas définies sur les valeurs par défaut.
[DisplayName("Error color")]
[Description("The color used on nodes containing errors.")]
[DefaultValue(Color.Red)]
public Color ErrorColor
{
...
}
Je souhaite simplement que IntelliSense de Visual Studio prenne en compte l'attribut Description
si aucun commentaire XML n'est trouvé. Cela éviterait de répéter la même phrase deux fois.
[Serializable]
est utilisé à tout moment pour la sérialisation et la désérialisation d'objets vers et à partir de sources de données externes telles que xml ou d'un serveur distant. Plus à ce sujet ici.
Dans l’esprit Hofstadt, l’attribut [Attribute]
est très utile, car c’est ainsi que vous créez vos propres attributs. J'ai utilisé des attributs au lieu d'interfaces pour implémenter des systèmes de plug-in, ajouter des descriptions à Enums, simuler plusieurs envois et autres astuces.
Ici est le post sur l'attribut intéressant InternalsVisibleTo . Fondamentalement, il reproduit les fonctionnalités d'accès des amis C++. C'est très pratique pour les tests unitaires.
J'ai trouvé [DefaultValue]
très utile.
Je suggérerais [TestFixture]
et [Test]
- à partir de la bibliothèque nUnit .
Les tests unitaires dans votre code garantissent la sécurité du refactoring et de la documentation codifiée.
[XmlIgnore]
car cela vous permet d'ignorer (dans toute sérialisation xml) les objets 'parents' qui pourraient sinon provoquer des exceptions lors de la sauvegarde.
Il n'est pas bien nommé, pas bien supporté dans le framework, et ne devrait pas nécessiter de paramètre, mais cet attribut est un marqueur utile pour les classes immuables:
[ImmutableObject(true)]
J'aime utiliser l'attribut [ThreadStatic]
en combinaison avec la programmation par thread et pile. Par exemple, si je veux une valeur que je veux partager avec le reste d’une séquence d’appel, mais que je veux le faire hors bande (c’est-à-dire en dehors des paramètres d’appel), je pourrais employer quelque chose comme ceci.
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;
}
}
Plus tard dans mon code, je peux l'utiliser pour fournir des informations contextuelles hors bande aux personnes en aval de mon code. Exemple:
using(new MyContextInformation(someInfoInContext)) {
...
}
L'attribut ThreadStatic me permet d'étendre l'appel uniquement au thread en question en évitant le problème compliqué d'accès aux données entre les threads.
DebuggerHiddenAttribute qui permet d’éviter l’introduction de code qui ne devrait pas être débogué.
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());
En outre, cela empêche d’afficher les méthodes dans la trace de pile, ce qui est utile lorsque vous avez une méthode qui englobe une autre méthode:
[DebuggerHidden]
public Element GetElementAt(Vector2 position)
{
return GetElementAt(position.X, position.Y);
}
public Element GetElementAt(Single x, Single y) { ... }
Si vous appelez maintenant GetElementAt(new Vector2(10, 10))
et qu'une erreur se produit au niveau de la méthode encapsulée, la pile d'appels n'affiche pas la méthode qui appelle la méthode qui génère l'erreur.
DesignerSerializationVisibilityAttribute
est très utile. Lorsque vous placez une propriété d'exécution sur un contrôle ou un composant et que vous ne voulez pas que le concepteur la sérialise, vous l'utilisez comme ceci:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Foo Bar {
get { return baz; }
set { baz = value; }
}
Le support du compilateur n’est supporté que par quelques attributs, mais l’utilisation des attributs dans AOP est très intéressante: PostSharp utilise vos attributs sur mesure pour injecter le langage de programmation dans les méthodes, permettant ainsi toutes sortes de capacités ... log/trace étant trivial exemples - mais quelques autres bons exemples sont des choses comme l'implémentation automatique de INotifyPropertyChanged ( here ).
Certaines qui se produisent et affectent directement le compilateur ou le runtime :
[Conditional("FOO")]
- les appels à cette méthode (y compris l'évaluation des arguments) ne se produisent que si le symbole "FOO" est défini pendant la construction[MethodImpl(...)]
- utilisé pour indiquer quelques éléments tels que la synchronisation, l'inline[PrincipalPermission(...)]
- utilisé pour injecter automatiquement des contrôles de sécurité dans le code[TypeForwardedTo(...)]
- utilisé pour déplacer des types entre des assemblages sans reconstruire les appelants Pour les choses vérifiées manuellement par réflexion - je suis un grand fan des attributs System.ComponentModel
; des éléments tels que [TypeDescriptionProvider(...)]
, [TypeConverter(...)]
et [Editor(...)]
, qui peuvent modifier complètement le comportement des types dans les scénarios de liaison de données (propriétés dynamiques, etc.).
J'ai utilisé le [DataObjectMethod]
récemment. Il décrit la méthode pour que vous puissiez utiliser votre classe avec ObjectDataSource (ou d'autres contrôles).
[DataObjectMethod(DataObjectMethodType.Select)]
[DataObjectMethod(DataObjectMethodType.Delete)]
[DataObjectMethod(DataObjectMethodType.Update)]
[DataObjectMethod(DataObjectMethodType.Insert)]
Si je devais faire une analyse de couverture de code, je pense que ces deux seraient top:
[Serializable]
[WebMethod]
Dans notre projet actuel, nous utilisons
[ComVisible(false)]
Il contrôle l'accessibilité d'un type géré individuel ou d'un membre, ou de tous les types au sein d'un assembly, à COM.
[TypeConverter(typeof(ExpandableObjectConverter))]
Demande au concepteur d’étendre les propriétés qui sont des classes (de votre contrôle)
[Obfuscation]
Ordonne aux outils d'obscurcissement d'effectuer les actions spécifiées pour un assembly, un type ou un membre. (Bien que vous utilisiez généralement un niveau d'assembly [Assembly:ObfuscateAssemblyAttribute(true)]
Les attributs que j'utilise le plus sont ceux liés à la sérialisation XML.
XmlRoot
XmlElement
XmlAttribute
etc...
Extrêmement utile pour toute analyse ou sérialisation XML rapide et sale.
[EditorBrowsable(EditorBrowsableState.Never)]
vous permet de masquer les propriétés et les méthodes d'IntelliSense si le projet ne fait pas partie de votre solution. Très utile pour cacher des flux non valides pour des interfaces fluides. À quelle fréquence voulez-vous GetHashCode () ou Equals ()?
Pour MVC, [ActionName("Name")]
vous permet d’avoir une action Get et une action Post avec la même signature de méthode, ou d’utiliser des tirets dans le nom de l’action, ce qui serait impossible autrement sans créer un itinéraire pour elle.
Être un développeur de niveau intermédiaire j'aime bien
System.ComponentModel.EditorBrowsableAttribute
Me permet de masquer les propriétés afin que le développeur de l'interface utilisateur ne soit pas submergé par des propriétés qu'il n'a pas besoin de voir.
System.ComponentModel.BindableAttribute
Certaines choses n'ont pas besoin d'être databound. Encore une fois, réduit le travail que les développeurs d'interface utilisateur doivent faire.
J'aime aussi la DefaultValue
mentionnée par Lawrence Johnston.
System.ComponentModel.BrowsableAttribute
et la Flags
sont utilisés régulièrement.
J'utilise System.STAThreadAttribute System.ThreadStaticAttribute
lorsque cela est nécessaire.
Au fait. Ceux-ci sont tout aussi précieux pour tous les développeurs de framework .Net.
J'estime qu'il est important de mentionner ici que les attributs suivants sont également très importants:
STAThreadAttribute
Indique que le modèle de threading COM d'une application est un appartement à un seul thread (STA).
Par exemple, cet attribut est utilisé dans les applications 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());
}
}
Et aussi ...
SuppressMessageAttribute
Supprime la notification d'une violation de règle spécifique de l'outil d'analyse statique, permettant ainsi plusieurs suppressions sur un seul artefact de code.
Par exemple:
[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;
}
Voici une liste rapide d’attributs prédéfinis que j’utilise réellement dans un grand projet (~ 500 000 lignes de contrôle):
Indicateurs, Serializable, WebMethod, COMVisible, TypeConverter, Conditionnel, ThreadStatic, Obsolète, InternalsVisibleTo, DebuggerStepThrough.
[DeploymentItem("myFile1.txt")]
document MSDN sur DeploymentItem
Ceci est très utile si vous testez un fichier ou utilisez le fichier comme entrée pour votre test.
Je génère une classe d'entité de données via CodeSmith et j'utilise des attributs pour une routine de validation. Voici un exemple:
/// <summary>
/// Firm ID
/// </summary>
[ChineseDescription("送样单位编号")]
[ValidRequired()]
public string FirmGUID
{
get { return _firmGUID; }
set { _firmGUID = value; }
}
Et j'ai une classe utilitaire pour effectuer la validation en fonction des attributs attachés à la classe d'entité de données. Voici le code:
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;
}
}
}
[System.Security.Permissions.PermissionSetAttribute]
permet aux actions de sécurité pour un PermissionSet d'être appliquées au code à l'aide de la sécurité déclarative.
// usage:
public class FullConditionUITypeEditor : UITypeEditor
{
// The immediate caller is required to have been granted the FullTrust permission.
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
public FullConditionUITypeEditor() { }
}
// on configuration sections
[ConfigurationProperty]
// in asp.net
[NotifyParentProperty(true)]
J'utilise toujours les attributs, [Serializable]
, [WebMethod]
, [DefaultValue]
, [Description("description here")]
.
mais à côté de cela il y a un attributs globaux en c #.
[Assembly: System.CLSCompliant(true)]
[Assembly: AssemblyCulture("")]
[Assembly: AssemblyDescription("")]