C#中的Attributes特性创建和结合反射应用举例
C#中的特性入门学习
Attributes官方介绍概述
Attributes provide a powerful method of associating metadata, or declarative information, with code (assemblies, types, methods, properties, and so forth). After an attribute is associated with a program entity, the attribute can be queried at run time by using a technique called reflection.
Attributes have the following properties:
Attributes add metadata to your program. Metadata is information about the types defined in a program. All .NET assemblies contain a specified set of metadata that describes the types and type members defined in the assembly. You can add custom attributes to specify any additional information that is required.
You can apply one or more attributes to entire assemblies, modules, or smaller program elements such as classes and properties.
Attributes can accept arguments in the same way as methods and properties.
Your program can examine its own metadata or the metadata in other programs by using reflection.
Reflection provides objects (of type Type) that 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. If you’re using attributes in your code, reflection enables you to access them. For more information, see Attributes.
翻译出来就是,特性提供了一种将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联的强大方法。将属性与程序实体关联后,可以使用反射技术在运行时查询该属性。
反射可以创建类型对象,比如程序集、模块。可以使用反射来动态创建类型的实例,将类型绑定到现有对象,或者从现有对象获取类型并调用其方法或访问其字段和属性。如果您在代码中使用特性,则反射可以访问它们并做相应的逻辑。
这些可以实现一些灵活多变的应用程序,比如图形编程,无代码编程,复杂动态变化实现简化等。
创建特性
public class AttTestAttribute : Attribute {
public string Desc { get; set; }
public AttTestAttribute ()
{
Console.WriteLine("AttTestAttribute 无参构造函数");
}
public AttTestAttribute (string desc) {
this.Desc = desc;
Console.WriteLine("AttTestAttribute 有参构造函数");
}
}
使用范围
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 // 结构体 接口 枚举 委托 等
举例
[AttTest("我在类上使用")]
public class Student {
[AttTest("我在字段上使用")]
public string name;
[AttTest("我在属性上使用")]
public string Name { get { return name; } set { name = value; } }
[AttTest("我在方法上使用")]
[return: AttTest("我在返回值上")]
public string GetName([AttTest("参数")] int Id) {
return name;
}
}
获取这些信息
static void Main(string[] args)
{
Student student=new Student() { Name="小明"};
Console.WriteLine(student.GetName(1));
Type type = typeof(Student);
//判断是否在类上使用特性
if (type.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)type.GetCustomAttribute(typeof(AttTestAttribute), true);
Console.WriteLine(customAttribute.Desc);
}
MethodInfo method = type.GetMethod("GetName");
//判断是否在方法上使用特性
if (method.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)method.GetCustomAttribute(typeof(AttTestAttribute), true);
Console.WriteLine(customAttribute.Desc);
}
ParameterInfo parameter = method.GetParameters()[0];
//判断是否在参数上使用特性
if (parameter.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)parameter.GetCustomAttributes(typeof(AttTestAttribute), true)[0];
Console.WriteLine(customAttribute.Desc);
}
ParameterInfo returnParameter = method.ReturnParameter;
//判断是否在方法的返回值上使用特性
if (returnParameter.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)returnParameter.GetCustomAttribute(typeof(AttTestAttribute), true);
Console.WriteLine(customAttribute.Desc);
}
PropertyInfo property = type.GetProperty("Name");
//判断是否在属性上使用特性
if (property.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)property.GetCustomAttribute(typeof(AttTestAttribute), true);
Console.WriteLine(customAttribute.Desc);
}
FieldInfo field = type.GetField("name");
//判断是否在字段上使用特性
if (field.IsDefined(typeof(AttTestAttribute), true))
{
AttTestAttribute customAttribute = (AttTestAttribute)field.GetCustomAttribute(typeof(AttTestAttribute), true);
Console.WriteLine(customAttribute.Desc);
}
Console.ReadKey();
}
结果:
```csharp
```csharp
小明
AttTestAttribute 有参构造函数
我在类上使用
AttTestAttribute 有参构造函数
我在方法上使用
AttTestAttribute 有参构造函数
参数
AttTestAttribute 有参构造函数
我在返回值上
AttTestAttribute 有参构造函数
我在属性上使用
AttTestAttribute 有参构造函数
我在字段上使用
常见用途
Common uses for attributes
The following list includes a few of the common uses of attributes in code:
Marking methods using the WebMethod attribute in Web services to indicate that the method should be callable over the SOAP protocol. For more information, see WebMethodAttribute.
Describing how to marshal method parameters when interoperating with native code. For more information, see MarshalAsAttribute.
Describing the COM properties for classes, methods, and interfaces.
Calling unmanaged code using the DllImportAttribute class.
Describing your assembly in terms of title, version, description, or trademark.
Describing which members of a class to serialize for persistence.
Describing how to map between class members and XML nodes for XML serialization.
Describing the security requirements for methods.
Specifying characteristics used to enforce security.
Controlling optimizations by the just-in-time (JIT) compiler so the code remains easy to debug.
Obtaining information about the caller to a method.
使用举例1用属性识别方法和参数,用反射调用方法
var myObject = new MyClass();
var methods = myObject.GetType().GetMethods();
var random = new Random();
var method = methods[random.Next(methods.Length)]; // 随机选择一个方法 ,也可以使用特性名称判断确定方法
var parameters = method.GetParameters();
var paramValues = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var paramType = parameters[i].ParameterType;
if (paramType == typeof(string))
{
paramValues[i] = Path.GetRandomFileName(); // 对于字符串类型,生成一个随机文件名作为参数值
}
else if (paramType.IsPrimitive || paramType == typeof(decimal))
{
paramValues[i] = Activator.CreateInstance(paramType); // 对于原始类型或decimal类型,创建一个默认值作为参数值
}
else
{
throw new NotSupportedException($"Unsupported parameter type: {paramType}");
}
}
var result = method.Invoke(myObject, paramValues); // 调用方法并获取其返回结果
Console.WriteLine(result); // 打印方法的返回结果
或者
public class Program
{
public static void Main()
{
var myObject = new MyClass();
var methodName = "MyMethod"; // 假设这是你要调用的方法的名称
var parameterTypes = new Type[] { typeof(string), typeof(int) }; // 假设这是你要调用的方法的参数类型
var parameters = new object[] { "Hello", 42 }; // 假设这是你要调用的方法的参数值
var method = myObject.GetType().GetMethod(methodName, parameterTypes);
var paramExpression = Expression.Constant(parameters);
var methodCallExpression = Expression.Call(method, paramExpression);
var lambdaExpression = Expression.Lambda<Func<object>>(methodCallExpression);
var result = lambdaExpression.Compile().Invoke();
Console.WriteLine(result); // 打印方法的返回结果
}
}
public class MyClass
{
public string MyMethod(string message, int number)
{
return message + " " + number.ToString();
}
}
使用举例2 使用特性排除某些类成员不参与XML序列化和反序列化
举例C#使用特性排除某些类成员不参与XML序列化和反序列化(https://blog.csdn.net/gy0124/article/details/134777545?spm=1001.2014.3001.5501)