Attributes provide a powerful way to associate metadata, or declarative information, with code (assemblies, types, methods, properties, and so on). After you associate an attribute with a program entity, you can query the attribute at run time by using a technique called reflection.
Attributes have the following properties:
Reflection APIs provided by Type describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. When you use attributes in your code, reflection enables you to access them. For more information, see Attributes.
Here's a simple example of reflection with the GetType() method. All types from the Object
base class inherit this method, which is used to obtain the type of a variable:
Note
Make sure you add the using System;
and using System.Reflection;
statements at the top of your C# (.cs) code file.
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
The output shows the type:
System.Int32
The following example uses reflection to obtain the full name of the loaded assembly.
// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);
The output is similar to the following example:
System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
Keyword differences for IL
The C# keywords protected
and internal
have no meaning in Intermediate Language (IL) and aren't used in the reflection APIs. The corresponding terms in IL are Family and Assembly. Here some ways you can use these terms:
internal
method by using reflection, use the IsAssembly property.protected internal
method, use the IsFamilyOrAssembly.Attributes can be placed on almost any declaration, though a specific attribute might restrict the types of declarations on which it's valid. In C#, you specify an attribute by placing the name of the attribute enclosed in square brackets ([]
) above the declaration of the entity to which it applies.
In this example, you use the SerializableAttribute attribute to apply a specific characteristic to a class:
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
You can declare a method with the DllImportAttribute attribute:
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
You can place multiple attributes on a declaration:
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
Some attributes can be specified more than once for a given entity. The following example shows multiuse of the ConditionalAttribute attribute:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
Note
By convention, all attribute names end with the suffix "Attribute" to distinguish them from other types in the .NET libraries. However, you don't need to specify the attribute suffix when you use attributes in code. For example, a [DllImport]
declaration is equivalent to a [DllImportAttribute]
declaration, but DllImportAttribute
is the actual name of the class in the .NET Class Library.
Many attributes have parameters, which can be positional, unnamed, or named. The following table describes how to work with named and positional attributes:
Positional parameters
Parameters of the attribute constructor:
Named parameters
Properties or fields of the attribute:
For example, the following code shows three equivalent DllImport
attributes:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
The first parameter, the DLL name, is positional and always comes first. The other instances are named parameters. In this scenario, both named parameters default to false, so they can be omitted. Refer to the individual attribute's documentation for information on default parameter values. For more information on allowed parameter types, see the Attributes section of the C# language specification.
Attribute targetsThe target of an attribute is the entity that the attribute applies to. For example, an attribute can apply to a class, a method, or an assembly. By default, an attribute applies to the element that follows it. But you can also explicitly identify the element to associate, such as a method, a parameter, or the return value.
To explicitly identify an attribute target, use the following syntax:
[target : attribute-list]
The following table shows the list of possible target
values.
assembly
Entire assembly module
Current assembly module field
Field in a class or a struct event
Event method
Method or get
and set
property accessors param
Method parameters or set
property accessor parameters property
Property return
Return value of a method, property indexer, or get
property accessor type
Struct, class, interface, enum, or delegate
You can specify the field
target value to apply an attribute to the backing field created for an automatically implemented property.
The following example shows how to apply attributes to assemblies and modules. For more information, see Common attributes (C#).
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
The following example shows how to apply attributes to methods, method parameters, and method return values 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; }
Note
Regardless of the targets on which the ValidatedContract
attribute is defined to be valid, the return
target has to be specified, even if the ValidatedContract
attribute is defined to apply only to return values. In other words, the compiler doesn't use the AttributeUsage
information to resolve ambiguous attribute targets. For more information, see AttributeUsage.
Here are some common ways to use attributes in code:
HttpPost
attribute. For more information, see the HttpPostAttribute class.Reflection is useful in the following scenarios:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3