Reflection and characteristic learning

Attributes are a way to associate additional data to properties (and other constructs). It does not rely on an exact match of option names and property names, and attributes can be used to specify additional metadata about the modified construct. Available attributes mark a property as Required and provide an option alias.

Attributes should be placed in a pair of square brackets before the modified construct, for example:

public class Person
{
    [CommandLineSwitchAlias("name")]
    public string name;

    [CommandLineSwitchRequired]
    public int level;
}

There are two ways to combine multiple attributes on the same construct. You can either separate multiple attributes with commas in the same square brackets, or you can put each attribute in its own pair of square brackets, for example:

public class Person
{
    [CommandLineSwitchRequired]
    [CommandLineSwitchAlias("name")]
    public string name;

    public int level;
}

In addition to modifying properties, attributes can modify classes, interfaces, structures, enumerations, delegates, events, methods, constructors, fields, parameters, return values, assemblies, type parameters, and modules. Most constructs can use square brackets to apply attributes as in the code above, but this syntax does not apply to return values, assemblies, and modules.

The properties of an assembly are used to add additional metadata about the assembly. For example, Visual Studio's "Project Wizard" generates an AssemblyInfo.cs file that contains a large number of properties related to the assembly.

Custom properties

It is easy to create custom properties. Properties are objects, so defining properties requires defining classes. After deriving from System.Attribute, a normal class becomes an attribute. For example:

public class CommandLineSwitchRequiredAttribute : Attribute
{

}

Find properties

In addition to providing properties to return type members, Type also provides methods to obtain attributes that modify the type. Similarly, all reflected types (such as PropertyInfo and MethodInfo) contain members to obtain a list of properties that modify the type.

The code for finding attributes is simple. Given a PropertyInfo object (obtained through reflection), call GetCustomAttributes(), specify the attributes to look for, and specify whether to check any overloaded methods. Alternatively, you can call the GetCustomAttributes() method without specifying the attribute type, thereby returning all attributes.

Initializing attributes using constructors

Calling GetCustomAttributes() returns an object array, which can be successfully converted into an Attribute array. The attribute in the code above does not have any instance members, so the only metadata information provided in the returned attribute is whether it is present, but attributes can also encapsulate data. For example:

public class CommandLineSwitchAliasAttribute : Attribute
{
    public string Alias{ get; private set; }

    public CommandLineSwitchAliasAttribute(string alias)
    {
        Alias = alias;
    }
}

public class Person
{
    [CommandLineSwitchAlias("l")]
    public int level;
}

To support this feature, you need to provide a constructor for the feature. Specifically, for aliases, you need to provide a constructor to get a string parameter. Similarly, if you wish to allow multiple aliases, the constructor should take an array of strings as a parameter.

When applying attributes to a construct, only constant values ​​and typeof expressions are allowed as arguments. This means that the attribute constructor requires parameters of the appropriate type. For example, providing a constructor to get an argument of type System.DateTime doesn't make much sense, because C# doesn't have a System.DateTime constant.

System.AttributeUsageAttribute

Most attributes only modify specific constructs. For example, it does not make sense to modify a class or assembly with the CommandLineOptionAttribute. To avoid inappropriate use of attributes, you can modify custom attributes with System.AttributeUsageAttribute (yes, attributes can modify attributes). For example:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class CommandLineSwitchRequiredAttribute : Attribute
{

}

[CommandLineSwitchRequired]    //报错,提示该特性只能修饰属性、索引器
public class Person
{
    
}

The constructor of AttributeUsageAttribute gets an AttributeTargets flag (flag). This enumeration provides a list of all targets that are allowed to be modified by the "runtime" attribute.

named parameters

In addition to limiting the targets modified by attributes, AttributeUsageAttribute can also specify whether to allow multiple copies of attributes on a structure. For example:

[AttributeUsage(AttributeTargets.Property | 
AttributeTargets.Field, 
AllowMultiple = true)]
public class CommandLineSwitchRequiredAttribute : Attribute
{

}

AllowMultiple is a named parameter that sets specific public properties and fields in an attribute constructor call---even if the constructor does not include corresponding parameters. Named parameters, although optional, allow setting additional instance data for a property without providing corresponding constructor parameters. Assignment of named parameters can only be done in the last part of the constructor, and any explicitly declared constructor parameters must be assigned before it.

With named parameters, you can directly assign values ​​to the attribute's data without having to provide a corresponding constructor for each combination of attribute attributes. Since many properties of a feature are optional, named parameters are often useful.

Guess you like

Origin blog.csdn.net/qq_42720695/article/details/124473409