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)