C# Language
Les attributs
Recherche…
Création d'un attribut personnalisé
//1) All attributes should be inherited from System.Attribute
//2) You can customize your attribute usage (e.g. place restrictions) by using System.AttributeUsage Attribute
//3) You can use this attribute only via reflection in the way it is supposed to be used
//4) MethodMetadataAttribute is just a name. You can use it without "Attribute" postfix - e.g. [MethodMetadata("This text could be retrieved via reflection")].
//5) You can overload an attribute constructors
[System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Class)]
public class MethodMetadataAttribute : System.Attribute
{
//this is custom field given just for an example
//you can create attribute without any fields
//even an empty attribute can be used - as marker
public string Text { get; set; }
//this constructor could be used as [MethodMetadata]
public MethodMetadataAttribute ()
{
}
//This constructor could be used as [MethodMetadata("String")]
public MethodMetadataAttribute (string text)
{
Text = text;
}
}
Utiliser un attribut
[StackDemo(Text = "Hello, World!")]
public class MyClass
{
[StackDemo("Hello, World!")]
static void MyMethod()
{
}
}
Lecture d'un attribut
La méthode GetCustomAttributes
renvoie un tableau d'attributs personnalisés appliqués au membre. Après avoir récupéré ce tableau, vous pouvez rechercher un ou plusieurs attributs spécifiques.
var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();
Ou itérer à travers eux
foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
Console.WriteLine(attribute.GetType());
}
GetCustomAttribute
méthode d'extension GetCustomAttribute
de System.Reflection.CustomAttributeExtensions
extrait un attribut personnalisé d'un type spécifié, il peut être appliqué à n'importe quel MemberInfo
.
var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));
GetCustomAttribute
également une signature générique pour spécifier le type d'attribut à rechercher.
var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();
Argument booléen inherit
peut être transmis à ces deux méthodes. Si cette valeur est définie sur true
les ancêtres de l'élément seront également inspectés.
Attribut DebuggerDisplay
L'ajout de l'attribut DebuggerDisplay
modifie la façon dont le débogueur affiche la classe lorsqu'il est survolé.
Les expressions enveloppées dans {}
seront évaluées par le débogueur. Cela peut être une propriété simple comme dans l'exemple suivant ou une logique plus complexe.
[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
L'ajout de ,nq
avant le crochet de fermeture supprime les guillemets lors de la sortie d'une chaîne.
[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]
Même si les expressions générales sont autorisées dans {}
elles ne sont pas recommandées. L'attribut DebuggerDisplay
sera écrit dans la métadonnée de l'assemblage sous forme de chaîne. Les expressions dans {}
ne sont pas vérifiées pour la validité. Ainsi, un attribut DebuggerDisplay
contenant une logique plus complexe que par exemple une arithmétique simple pourrait fonctionner correctement en C #, mais la même expression évaluée dans VB.NET ne sera probablement pas syntaxiquement valide et produira une erreur lors du débogage.
Une façon de rendre DebuggerDisplay
plus agnostique en DebuggerDisplay
langage consiste à écrire l'expression dans une méthode ou une propriété et à l'appeler à la place.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
private string DebuggerDisplay()
{
return $"{StringProperty} - {IntProperty}"";
}
}
On peut souhaiter que DebuggerDisplay
toutes ou certaines propriétés et lors du débogage et de l'inspection du type d'objet.
L'exemple ci-dessous entoure également la méthode d'assistance avec #if DEBUG
car DebuggerDisplay
est utilisé dans les environnements de débogage.
[DebuggerDisplay("{DebuggerDisplay(),nq}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
#if DEBUG
private string DebuggerDisplay()
{
return
$"ObjectId:{this.ObjectId}, StringProperty:{this.StringProperty}, Type:{this.GetType()}";
}
#endif
}
Attributs d'information de l'appelant
Les attributs d'information de l'appelant peuvent être utilisés pour transmettre des informations sur l'invocateur à la méthode invoquée. La déclaration ressemble à ceci:
using System.Runtime.CompilerServices;
public void LogException(Exception ex,
[CallerMemberName]string callerMemberName = "",
[CallerLineNumber]int callerLineNumber = 0,
[CallerFilePath]string callerFilePath = "")
{
//perform logging
}
Et l'invocation ressemble à ceci:
public void Save(DBContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
LogException(ex);
}
}
Notez que seul le premier paramètre est passé explicitement à la méthode LogException
alors que les autres seront fournis au moment de la compilation avec les valeurs appropriées.
Le paramètre callerMemberName
recevra la valeur "Save"
- le nom de la méthode d'appel.
Le paramètre callerLineNumber
recevra le numéro de la ligne sur LogException
appel de méthode LogException
est écrit.
Et le paramètre 'callerFilePath' recevra le chemin complet du fichier dans lequel la méthode Save
est déclarée.
Lecture d'un attribut depuis l'interface
Il n'y a pas de moyen simple d'obtenir des attributs à partir d'une interface, car les classes n'héritent pas des attributs d'une interface. Chaque fois que vous implémentez une interface ou que vous remplacez des membres dans une classe dérivée, vous devez déclarer à nouveau les attributs. Donc, dans l'exemple ci-dessous, le résultat serait True
dans les trois cas.
using System;
using System.Linq;
using System.Reflection;
namespace InterfaceAttributesDemo {
[AttributeUsage(AttributeTargets.Interface, Inherited = true)]
class MyCustomAttribute : Attribute {
public string Text { get; set; }
}
[MyCustomAttribute(Text = "Hello from interface attribute")]
interface IMyClass {
void MyMethod();
}
class MyClass : IMyClass {
public void MyMethod() { }
}
public class Program {
public static void Main(string[] args) {
GetInterfaceAttributeDemo();
}
private static void GetInterfaceAttributeDemo() {
var attribute1 = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute), true);
Console.WriteLine(attribute1 == null); // True
var attribute2 = typeof(MyClass).GetCustomAttributes(true).OfType<MyCustomAttribute>().SingleOrDefault();
Console.WriteLine(attribute2 == null); // True
var attribute3 = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>(true);
Console.WriteLine(attribute3 == null); // True
}
}
}
Une façon de récupérer les attributs d'interface consiste à les rechercher via toutes les interfaces implémentées par une classe.
var attribute = typeof(MyClass).GetInterfaces().SelectMany(x => x.GetCustomAttributes().OfType<MyCustomAttribute>()).SingleOrDefault();
Console.WriteLine(attribute == null); // False
Console.WriteLine(attribute.Text); // Hello from interface attribute
Attribut obsolète
System.Obsolete est un attribut utilisé pour marquer un type ou un membre qui a une meilleure version et ne doit donc pas être utilisé.
[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
//
}
Si la classe ci-dessus est utilisée, le compilateur affichera l'avertissement "Cette classe est obsolète. Utilisez plutôt SomeOtherClass".