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; }
}

DebuggerDisplay Exempel

,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."



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow