Megosztás a következőn keresztül:


Egyéni attribútumok definiálása és olvasása

Az attribútumok lehetővé teszik az információk deklaratív módon való társítását a kódhoz. Emellett olyan újrafelhasználható elemet is biztosíthatnak, amely különböző célokra alkalmazható. Fontolja meg a ObsoleteAttribute. Alkalmazható osztályokra, szerkezetekre, metódusokra, konstruktorokra stb. Deklarálja, hogy az elem elavult. Ezután a C#-fordítón múlik, hogy megkeresse ezt az attribútumot, és végrehajtson néhány műveletet válaszként.

Ebben az oktatóanyagban megtudhatja, hogyan adhat hozzá attribútumokat a kódhoz, hogyan hozhat létre és használhat saját attribútumokat, és hogyan használhatja a .NET-be beépített attribútumokat.

Előfeltételek

Be kell állítania a gépet a .NET futtatására. A telepítési utasításokat a .NET Letöltések oldalán találja. Ezt az alkalmazást Windows, Ubuntu Linux, macOS vagy Docker-tárolóban is futtathatja. Telepítenie kell a kedvenc kódszerkesztőt. Az alábbi leírások a Visual Studio Code-ot használják, amely nyílt forráskódú, platformfüggetlen szerkesztő. Azonban bármilyen eszközt használhat, amely kényelmes az Ön számára.

Az alkalmazás létrehozása

Most, hogy telepítette az összes eszközt, hozzon létre egy új .NET-konzolalkalmazást. A parancssori generátor használatához hajtsa végre a következő parancsot a kedvenc shell (parancsértelmező) programjában:

dotnet new console

Ez a parancs csupasz .NET-projektfájlokat hoz létre. Futtassa dotnet restore a projekt fordításához szükséges függőségek visszaállítását.

Nem kell futtatnia dotnet restore, mert az összes olyan parancs implicit módon fut, amely visszaállítást igényel, például dotnet new, dotnet build, dotnet run, dotnet test, dotnet publishés dotnet pack. Az implicit visszaállítás letiltásához használja a --no-restore lehetőséget.

A dotnet restore parancs továbbra is hasznos bizonyos esetekben, amikor a explicit visszaállításnak van értelme, például folyamatos integrációs buildeket az Azure DevOps Services vagy olyan buildrendszerekben, amelyeknek explicit módon kell szabályozni a visszaállítást.

További információ a NuGet-hírcsatornák kezeléséről: dotnet restore dokumentáció.

A program végrehajtásához használja a következőt dotnet run: . A konzolon a "Hello, World" kimenetnek kell megjelennie.

Attribútumok hozzáadása a kódhoz

A C#-ban az attribútumok az alaposztálytól Attribute öröklő osztályok. Minden olyan osztály, amelytől öröklődik Attribute , egyfajta "címkeként" használható más kódrészleteken. Van például egy úgynevezett attribútum ObsoleteAttribute. Ez az attribútum azt jelzi, hogy a kód elavult, és nem szabad többé használni. Ezt az attribútumot például szögletes zárójelek használatával helyezheti el egy osztályban.

[Obsolete]
public class MyClass
{
}

Bár az osztály neve ObsoleteAttribute, csak [Obsolete]-t kell használni a kódban. A legtöbb C#-kód ezt az egyezményt követi. Ha úgy dönt, használhatja a teljes nevet [ObsoleteAttribute] .

Ha elavultként jelöl meg egy osztályt, érdemes információt adni arról, hogy miért elavult, és/vagy mit érdemes használni helyette. Ennek a magyarázatnak a megadásához sztringparamétert kell megadnia az Elavult attribútumhoz.

[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{
}

A sztringet argumentumként adják át egy ObsoleteAttribute konstruktornak, mintha ezt írnánk: var attr = new ObsoleteAttribute("some string").

Az attribútumkonstruktor paraméterei egyszerű típusokra/literálokra korlátozódnak: bool, int, double, string, Type, enums, etc és az ilyen típusú tömbökre. Kifejezés vagy változó nem használható. Szabadon használhat pozíciós vagy elnevezett paramétereket.

Saját attribútum létrehozása

Attribútumot úgy hozhat létre, hogy definiál egy új osztályt, amely az Attribute alaposztálytól öröklődik.

public class MySpecialAttribute : Attribute
{
}

A korábbi kód segítségével attribútumként használhatja a [MySpecial] (vagy [MySpecialAttribute]) elemeket a kódbázis más részein.

[MySpecial]
public class SomeOtherClass
{
}

A .NET alaposztálytár attribútumai, mint például ObsoleteAttribute, bizonyos viselkedéseket váltanak ki a fordítóprogramban. A létrehozott attribútumok azonban csak metaadatokként viselkednek, és nem eredményeznek semmilyen kódot az attribútumosztályon belül. Önön múlik, hogy az adott metaadatokat a kód más részein hajtja végre.

Itt van egy buktató, amire figyelni kell. Ahogy korábban említettük, attribútumok használatakor csak bizonyos típusok adhatóak át argumentumként. Attribútumtípus létrehozásakor azonban a C#-fordító nem akadályozza meg ezen paraméterek létrehozását. Az alábbi példában létrehozott egy attribútumot egy megfelelően lefordított konstruktorral.

public class GotchaAttribute : Attribute
{
    public GotchaAttribute(Foo myClass, string str)
    {
    }
}

Ezt a konstruktort azonban nem használhatja attribútumszintaxissal.

[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{
}

Az előző kód fordítóhibát okoz, például Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type

Attribútumhasználat korlátozása

Az attribútumok a következő "célokon" használhatók. Az előző példák az osztályokon mutatják be őket, de a következőkkel is használhatók:

  • Összeszerelés
  • Osztály
  • Konstruktor
  • Képviselő
  • Enumeráció
  • Esemény
  • szakterület
  • GenerikusParaméter
  • Interfész
  • Metódus
  • Modul
  • Paraméter
  • Ingatlan
  • ReturnValue
  • Struktúra

Attribútumosztály létrehozásakor a C# alapértelmezés szerint lehetővé teszi az attribútum használatát bármely lehetséges attribútum-célon. Ha bizonyos célokra szeretné korlátozni az attribútumot, ezt az AttributeUsageAttribute attribútumosztályon keresztül teheti meg. Igen, egy tulajdonság egy másik tulajdonságban!

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{
}

Ha a fenti attribútumot olyanra próbálja helyezni, amely nem osztály vagy szerkezet, akkor egy fordítóhiba jelenik meg, például Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarations

public class Foo
{
    // if the below attribute was uncommented, it would cause a compiler error
    // [MyAttributeForClassAndStructOnly]
    public Foo()
    { }
}

Kódelemhez csatolt attribútumok használata

Az attribútumok metaadatként működnek. Külső erő nélkül nem csinálnak semmit.

Az attribútumok megkereséséhez és az azokra való reagáláshoz reflexióra van szükség. A reflexió lehetővé teszi, hogy olyan kódot írjon C# nyelven, amely más kódot vizsgál. Használhatja például a Reflectiont egy osztály adatainak lekéréséhez (a kód elején adja hozzá using System.Reflection; ):

TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);

Ez a következőhöz hasonlót nyomtat: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Miután rendelkezik egy TypeInfo objektummal (vagy egy MemberInfo, vagy FieldInfomás objektummal), használhatja a metódust GetCustomAttributes . Ez a metódus objektumgyűjteményt Attribute ad vissza. Attribútumtípust is használhat GetCustomAttribute és megadhat.

Íme egy példa a GetCustomAttributes használatára egy MemberInfo példányon MyClass érdekében (amelyet korábban láttunk, hogy [Obsolete] attribútum van rajta).

var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
    Console.WriteLine("Attribute on MyClass: " + attr.GetType().Name);

Ez a konzolra nyomtatja a következőt: Attribute on MyClass: ObsoleteAttribute. Próbáljon meg más attribútumokat hozzáadni a fájlhoz MyClass.

Fontos megjegyezni, hogy ezek az Attribute objektumok lazán vannak példányosítva. Vagyis nincsenek példányosítva, amíg nem használja a GetCustomAttribute vagy a GetCustomAttributes elemet. Ők is minden alkalommal példányosítódnak. Ha kétszer egymás után meghívja a GetCustomAttributes, akkor két különböző ObsoleteAttribute példányt ad vissza.

Gyakori attribútumok a futtatókörnyezetben

Az attribútumokat számos eszköz és keretrendszer használja. Az NUnit olyan attribútumokat használ, mint a [Test] és [TestFixture], amelyeket az NUnit tesztfuttató használ. ASP.NET MVC az MVC-hez hasonló [Authorize] attribútumokat használ, és egy műveletszűrő keretrendszert biztosít az MVC-műveletek átfogó problémáinak végrehajtásához. A PostSharp az attribútumszintaxis használatával engedélyezi a C#-ban a szempontorientált programozást.

Íme néhány figyelemre méltó attribútum a .NET Core alaposztály-kódtárakba:

  • [Obsolete]. Ezt a fenti példákban használták, és a System névtérben él. Hasznos deklaratív dokumentációt nyújtani egy változó kódbázisról. Egy üzenet sztring formájában is megadható, és egy másik logikai paraméter használatával fordítói figyelmeztetésről fordítói hibára eszkalálható.
  • [Conditional]. Ez az attribútum a System.Diagnostics névtérben található. Ez az attribútum alkalmazható metódusokra (vagy attribútumosztályokra). Sztringet kell átadnia a konstruktornak. Ha ez a sztring nem egyezik meg egy irányelvvel #define , akkor a C#-fordító eltávolítja az adott metódusra irányuló hívásokat (de magát a metódust nem). Ezt a technikát általában hibakeresési (diagnosztikai) célokra használja.
  • [CallerMemberName]. Ez az attribútum paramétereken használható, és a System.Runtime.CompilerServices névtérben található. CallerMemberName egy attribútum, amely egy másik metódust hívó metódus nevének injektálására szolgál. Ez egy módja annak, hogy kiküszöbölje a "mágikus sztringeket" az INotifyPropertyChanged implementálása során a különböző felhasználói felületi keretrendszerekben. Példaként:
public class MyUIClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    public void RaisePropertyChanged([CallerMemberName] string propertyName = default!)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string? _name;
    public string? Name
    {
        get { return _name;}
        set
        {
            if (value != _name)
            {
                _name = value;
                RaisePropertyChanged();   // notice that "Name" is not needed here explicitly
            }
        }
    }
}

A fenti kódban nem kell literális "Name" sztringet megadnia. A használat CallerMemberName megakadályozza a elírással kapcsolatos hibákat, és gördülékenyebb újrabontást/átnevezést tesz lehetővé. Az attribútumok deklaratív hatalmat adnak a C#-nak, de a kód metaadat-formája, és nem önállóan működnek.