C# Language
attribut
Sök…
Skapa ett anpassat attribut
//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;
}
}
Använda ett attribut
[StackDemo(Text = "Hello, World!")]
public class MyClass
{
[StackDemo("Hello, World!")]
static void MyMethod()
{
}
}
Läser ett attribut
Metod GetCustomAttributes
returnerar en rad anpassade attribut som tillämpas på medlemmen. När du har hämtat den här arrayen kan du söka efter ett eller flera specifika attribut.
var attribute = typeof(MyClass).GetCustomAttributes().OfType<MyCustomAttribute>().Single();
Eller iterera igenom dem
foreach(var attribute in typeof(MyClass).GetCustomAttributes()) {
Console.WriteLine(attribute.GetType());
}
GetCustomAttribute
förlängningsmetoden från System.Reflection.CustomAttributeExtensions
hämtar ett anpassat attribut av en specificerad typ, det kan tillämpas på valfritt MemberInfo
.
var attribute = (MyCustomAttribute) typeof(MyClass).GetCustomAttribute(typeof(MyCustomAttribute));
GetCustomAttribute
har också generisk signatur för att ange typ av attribut som du vill söka efter.
var attribute = typeof(MyClass).GetCustomAttribute<MyCustomAttribute>();
Boolskt argument inherit
kan överföras till båda dessa metoder. Om detta värde är satt till true
förfäderna till element också inspekteras.
DebuggerDisplay-attribut
Om du lägger till DebuggerDisplay
attributet kommer det att ändra hur felsökaren visar klassen när den hålls över.
Uttryck som är inslagna i {}
kommer att utvärderas av felsökaren. Detta kan vara en enkel egenskap som i följande exempel eller mer komplex logik.
[DebuggerDisplay("{StringProperty} - {IntProperty}")]
public class AnObject
{
public int ObjectId { get; set; }
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
,nq
lägger till ,nq
innan stängningsfästet tas bort citat när du matar ut en sträng.
[DebuggerDisplay("{StringProperty,nq} - {IntProperty}")]
Även om allmänna uttryck är tillåtna i {}
rekommenderas de inte. Attributen DebuggerDisplay
kommer att skrivas in i monteringsmetadata som en sträng. Uttryck i {}
kontrolleras inte för giltighet. Så ett DebuggerDisplay
attribut som innehåller mer komplex logik än dvs. någon enkel aritmetik kan fungera bra i C #, men samma uttryck som utvärderas i VB.NET kommer förmodligen inte att vara syntaktiskt giltigt och producera ett fel under felsökning.
Ett sätt att göra DebuggerDisplay
mer språkagnostiskt är att skriva uttrycket i en metod eller egenskap och kalla det istället.
[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}"";
}
}
Man kanske vill att DebuggerDisplay
ska mata ut alla eller bara några av egenskaperna och vid felsökning och inspektering också objektets typ.
Exemplet nedan omger även #if DEBUG
med #if DEBUG
eftersom DebuggerDisplay
används i felsökningsmiljöer.
[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
}
Attribut för samtalinfo
Attribut för anropsinfo kan användas för att skicka information om invokaren till den åberopade metoden. Förklaringen ser ut så här:
using System.Runtime.CompilerServices;
public void LogException(Exception ex,
[CallerMemberName]string callerMemberName = "",
[CallerLineNumber]int callerLineNumber = 0,
[CallerFilePath]string callerFilePath = "")
{
//perform logging
}
Och kallelsen ser så här ut:
public void Save(DBContext context)
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
LogException(ex);
}
}
Observera att endast den första parametern överförs uttryckligen till LogException
metoden medan resten av dem kommer att tillhandahållas vid sammanställningstiden med relevanta värden.
Parametern callerMemberName
får värdet "Save"
- namnet på samtalsmetoden.
Parametern callerLineNumber
får numret på vilken rad som LogException
för LogException
metoden är skrivet på.
Och "callerFilePath" -parametern får den fulla sökvägen för filen Save
metoden deklareras i.
Läser ett attribut från gränssnittet
Det finns inget enkelt sätt att få attribut från ett gränssnitt, eftersom klasser inte ärver attribut från ett gränssnitt. När du implementerar ett gränssnitt eller åsidosätter medlemmar i en härledd klass måste du deklarera attributen igen. Så i exemplet nedan skulle output vara True
i alla tre fallen.
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
}
}
}
Ett sätt att hämta gränssnittsattribut är att söka efter dem genom alla gränssnitt som implementeras av en klass.
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
Föråldrad attribut
System.Obsolete är ett attribut som används för att markera en typ eller ett medlem som har en bättre version och därför inte bör användas.
[Obsolete("This class is obsolete. Use SomeOtherClass instead.")]
class SomeClass
{
//
}
Om klassen ovan används, kommer kompilatorn att varna "Denna klass är föråldrad. Använd SomeOtherClass istället."