Condividi tramite


Attributi

Gli attributi offrono un modo efficace per associare metadati o informazioni dichiarative al codice (assembly, tipi, metodi, proprietà e così via). Dopo aver associato un attributo a un'entità programma, è possibile eseguire una query sull'attributo in fase di esecuzione usando una tecnica denominata reflection.

Gli attributi hanno le proprietà seguenti:

  • Gli attributi aggiungono metadati al programma. metadati sono informazioni sui tipi definiti in un programma. Tutti gli assembly .NET contengono un set specificato di metadati che descrivono i tipi e i membri di tipo definiti nell'assembly. È possibile aggiungere attributi personalizzati per specificare eventuali altre informazioni necessarie.
  • Gli attributi possono essere applicati a interi assembly, moduli o elementi di programma più piccoli, ad esempio classi e proprietà.
  • Gli attributi possono accettare argomenti nello stesso modo dei metodi e delle proprietà.
  • Gli attributi consentono a un programma di esaminare i propri metadati, o i metadati di altri programmi, tramite il meccanismo di riflessione.

Usare la reflection

Riflessione: Le API fornite da Type descrivono assembly, moduli e tipi. È possibile utilizzare la reflection per creare in modo dinamico un'istanza di un tipo, associare il tipo a un oggetto esistente oppure ottenere il tipo da un oggetto esistente e richiamarne i metodi o accedere ai relativi campi e proprietà. Quando si usano attributi nel codice, la reflection consente di accedervi. Per altre informazioni, vedere Attributi.

Ecco un semplice esempio di reflection con il metodo GetType(). Tutti i tipi della Object classe base ereditano questo metodo, che viene usato per ottenere il tipo di una variabile:

Nota

Assicurati di aggiungere le istruzioni using System; e using System.Reflection; all'inizio del file di codice C# (.cs).

// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);

Il risultato mostra il tipo:

System.Int32

Nell'esempio seguente viene utilizzata la reflection per ottenere il nome completo dell'assembly caricato.

// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);

L'output è simile all'esempio seguente:

System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

Differenze tra parole chiave per IL

Le parole chiave protected C# e internal non hanno alcun significato nel linguaggio intermedio (IL) e non vengono usate nelle API di reflection. I termini corrispondenti in IL sono Family e Assembly. Ecco alcuni modi in cui è possibile usare questi termini:

  • Per identificare un internal metodo tramite reflection, utilizzare la IsAssembly proprietà .
  • Per identificare un metodo protected internal, usare il IsFamilyOrAssembly.

Usare gli attributi

Gli attributi possono essere inseriti in quasi qualsiasi dichiarazione, anche se un attributo specifico potrebbe limitare i tipi di dichiarazioni su cui è valido. In C# si specifica un attributo inserendo il nome dell'attributo racchiuso tra parentesi quadre ([]) sopra la dichiarazione dell'entità a cui si applica.

In questo esempio si usa l'attributo SerializableAttribute per applicare una caratteristica specifica a una classe:

[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

È possibile dichiarare un metodo con l'attributo DllImportAttribute :

[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

È possibile inserire più attributi in una dichiarazione:

void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }

Alcuni attributi possono essere specificati più volte per una determinata entità. L'esempio seguente mostra l'uso multiuso dell'attributo ConditionalAttribute :

[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
    // ...
}

Nota

Per convenzione, tutti i nomi degli attributi terminano con il suffisso "Attribute" per distinguerli da altri tipi nelle librerie .NET. Tuttavia, non è necessario specificare il suffisso dell'attributo quando si usano attributi nel codice. Ad esempio, una [DllImport] dichiarazione equivale a una [DllImportAttribute] dichiarazione, ma DllImportAttribute è il nome effettivo della classe nella libreria di classi .NET.

Parametri dell'attributo

Molti attributi hanno parametri, che possono essere posizionali, senza nome o denominati. La tabella seguente descrive come usare gli attributi denominati e posizionali:

Parametri posizionali

Parametri del costruttore dell'attributo:

Parametri denominati

Proprietà o campi dell'attributo:

  • Deve specificare, non può omettere
  • Specificare sempre prima
  • Specificare in un determinato ordine
  • Sempre facoltativo, omettere quando false
  • Specificare i parametri posizionali successivamente
  • Specificare in qualsiasi ordine

Ad esempio, il codice seguente mostra tre attributi equivalenti DllImport :

[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]

Il primo parametro, il nome della DLL, è posizionale e viene sempre prima. Le altre istanze sono denominate parametri. In questo scenario, entrambi i parametri denominati hanno valore predefinito su false, in modo che possano essere omessi. Per informazioni sui valori dei parametri predefiniti, vedere la documentazione dell'attributo singolo. Per altre informazioni sui tipi di parametro consentiti, vedere la sezione attributi della specifica del linguaggio C# .

Destinazioni degli attributi

Il target di un attributo è l'entità a cui si applica l'attributo. Ad esempio, un attributo può essere applicato a una classe, a un metodo o a un assembly. Per impostazione predefinita, un attributo si applica all'elemento che lo segue. Ma è anche possibile identificare in modo esplicito l'elemento da associare, ad esempio un metodo, un parametro o il valore restituito.

Per identificare in modo esplicito una destinazione dell'attributo, usare la sintassi seguente:

[target : attribute-list]

Nella tabella seguente viene illustrato l'elenco dei valori possibili target .

Valore di destinazione Si applica a
assembly Intero assemblaggio
module Modulo corrente di assemblaggio
field Campo in una classe o in una struttura
event Evento
method Funzioni di accesso alle proprietà di metodo o getset e di set
param Parametri del metodo o parametri della funzione di accesso alle proprietà set
property Proprietà
return Valore restituito di un metodo, di un indicizzatore di proprietà o di una funzione di accesso alla proprietà get
type Struct, classe, interfaccia, enumerazione o delegato

È possibile specificare il field valore di destinazione per applicare un attributo al campo sottostante creato per una proprietà implementata automaticamente.

Nell'esempio seguente viene illustrato come applicare attributi agli assembly e ai moduli. Per altre informazioni, vedere Attributi comuni (C#).

using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]

Nell'esempio seguente viene illustrato come applicare attributi a metodi, parametri del metodo e valori restituiti dal metodo in C#.

// default: applies to method
[ValidatedContract]
int Method1() { return 0; }

// applies to method
[method: ValidatedContract]
int Method2() { return 0; }

// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }

// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }

Nota

Indipendentemente dalle destinazioni in cui l'attributo ValidatedContract è definito come valido, è necessario specificare la return destinazione, anche se l'attributo ValidatedContract è definito per applicare solo ai valori restituiti. In altre parole, il compilatore non usa le AttributeUsage informazioni per risolvere le destinazioni di attributi ambigue. Per altre informazioni, vedere AttributeUsage.

Esaminare i modi per usare gli attributi

Ecco alcuni modi comuni per usare gli attributi nel codice:

  • Contrassegnare i metodi del controller che rispondono ai messaggi POST usando l'attributo HttpPost . Per altre informazioni, vedere la classe HttpPostAttribute.
  • Descrivere come effettuare il marshalling dei parametri del metodo durante l'interoperabilità con il codice nativo. Per altre informazioni, vedere la classe MarshalAsAttribute.
  • Descrivere le proprietà COM (Component Object Model) per classi, metodi e interfacce.
  • Chiamare il codice non gestito usando la DllImportAttribute classe .
  • Descrivi il tuo assembly in termini di titolo, versione, descrizione o marchio.
  • Descrivere i membri di una classe da serializzare per la persistenza.
  • Descrivere come eseguire il mapping tra i membri della classe e i nodi XML per la serializzazione XML.
  • Descrivere i requisiti di sicurezza per i metodi.
  • Specificare le caratteristiche utilizzate per applicare la sicurezza.
  • Ottimizzazioni dei controlli con il compilatore JIT (Just-In-Time) in modo che il codice rimanga facile da eseguire.
  • Ottenere informazioni sul chiamante di un metodo.

Esaminare gli scenari di riflessione

La riflessione è utile negli scenari seguenti: