C# 特性
定义 :特性是一种类,继承自Attribute类,可以用于修饰类、方法、属性、字段、参数等,用于为它们添加元数据,以便在运行时通过反射获取它们。
命名规范:以Attribute结尾,如SerializableAttribute。
分类:内置特性、自定义特性。
创建特性
- 定义特性类,继承自Attribute类
- 标记,使用反射获取特性
- 调用
简单的例子
// 定义特性,继承自Attribute类
class MyAttribute : Attribute
{
public MyAttribute(string showInfo) {
this.ShowInfo = showInfo;
}
public string ShowInfo { get; set; }
}
// 使用特性
[My("这是一个特性")]
class UseAttribute
{
// 通过反射调用特性
public void Test01( ) {
Type type = typeof(UseAttribute);
object[] objs = type.GetCustomAttributes(true);
foreach (object obj in objs) {
MyAttribute? myAttribute = obj as MyAttribute;
if (myAttribute != null) {
Console.WriteLine(myAttribute.ShowInfo);
}
}
}
}
class Program {
static void Main(string[] args) {
UseAttribute useAttribute = new UseAttribute();
useAttribute.Test01();
}
}
简单的场景1
定义一个枚举,然后给枚举的每个值添加一个特性,然后使用反射获取特性,就可以获取到枚举的值的特性了。
enum UserState
{
/// <summary>
/// 正常
/// </summary>
[Remark("正常")]
Normal = 0,
/// <summary>
/// 冻结
/// </summary>
[Remark("冻结")]
Frozen = 1,
/// <summary>
/// 删除
/// </summary>
[Remark("删除")]
Deleted = 2
}
使用反射获取特性
class AttributeInvoke
{
/// <summary>
/// 获取枚举的特性
/// </summary>
public string GetRemark(UserState userState)
{
Type type = userState.GetType();
// 获取枚举的字段
var field = type.GetField(userState.ToString());
// 获取字段上的特性
if (field?.IsDefined(typeof(RemarkAttribute), true) == true)
{
if (field.GetCustomAttribute(
typeof(RemarkAttribute), true) is RemarkAttribute remarkAttribute)
{
return remarkAttribute.Remark;
}
}
return userState.ToString();
}
}
调用测试
class Program
{
static void Main(string[] args)
{
// UseAttribute useAttribute = new UseAttribute();
// useAttribute.Test01();
// 场景1:
UserState userState = UserState.Frozen;
// if 条件判断写法
// if (userState == UserState.Normal)
// {
// Console.WriteLine("正常");
// }
// else if (userState == UserState.Frozen)
// {
// Console.WriteLine("冻结");
// }
// else if (userState == UserState.Deleted)
// {
// Console.WriteLine("删除");
// }
// 这样写很麻烦,且改动不方便
// 使用特性加反射
AttributeInvoke attributeInvoke = new();
Console.WriteLine(attributeInvoke.GetRemark(userState));
}
}
场景2
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class ShowAttribute : Attribute
{
public ShowAttribute(string showInfo)
{
ShowInfo = showInfo;
}
public void Show()
{
Console.WriteLine(ShowInfo);
}
public string ShowInfo { get; private set; }
}
定义一个类,然后在类上、方法上、属性上、字段上使用特性
[Show("我是在类上的特性")]
[Show("我是在类上的特性2")]
public class ShowTest
{
[Show("我是在方法上的特性")]
public void Test()
{
}
[Show("我是在属性上的特性")]
public string TestProperty { get; set; }
[Show("我是在字段上的特性")]
public string TestField;
}
然后使用反射获取特性,就可以获取到类上、方法上、属性上、字段上的特性了
public static class InvokeConter
{
public static void InvonkeManager<T>(this T showTest) where T : new()
{
Type type = showTest.GetType();
if (type.IsDefined(typeof(ShowAttribute), true))
{
// 获取类上的特性
object[] attribues = type.GetCustomAttributes(typeof(ShowAttribute), true);
foreach (ShowAttribute attribue in attribues)
{
attribue.Show();
}
// 获取方法上的特性
foreach (var method in type.GetMethods())
{
if (method.IsDefined(typeof(ShowAttribute), true))
{
object[] attribues1 = method.GetCustomAttributes(typeof(ShowAttribute), true);
foreach (ShowAttribute attribue in attribues1)
{
attribue.Show();
}
}
}
// 获取属性上的特性
foreach (var property in type.GetProperties())
{
if (property.IsDefined(typeof(ShowAttribute), true))
{
object[] attribues1 = property.GetCustomAttributes(typeof(ShowAttribute), true);
foreach (ShowAttribute attribue in attribues1)
{
attribue.Show();
}
}
}
// 获取字段上的特性
foreach (var field in type.GetFields())
{
if (field.IsDefined(typeof(ShowAttribute), true))
{
object[] attribues1 = field.GetCustomAttributes(typeof(ShowAttribute), true);
foreach (ShowAttribute attribue in attribues1)
{
attribue.Show();
}
}
}
}
}
}
测试
class Test
{
static void Main(string[] args)
{
// 普通调用方式
// InvokeConter invokeConter = new();
// invokeConter.InvonkeManager(new ShowTest());
// 扩展方法
ShowTest showTest = new();
showTest.InvonkeManager();
}
}
特性实现验证数据
定义一个抽象类,继承自Attribute类,实现一个抽象方法,用于验证数据,然后在需要验证的属性上使用特性,然后在需要验证的时候调用Validate方法,就可以验证数据了。
public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object objValue);
}
定义几个特性,继承自抽象类,实现抽象方法,用于验证数据。
/// <summary>
/// 验证是否为空
/// </summary>
public class RequiredAttribute : AbstractValidateAttribute
{
public override bool Validate(object objValue)
{
return objValue != null && !string.IsNullOrWhiteSpace(objValue.ToString());
}
}
/// <summary>
/// 验证字符串长度
/// </summary>
public class StringLengthAttribute : AbstractValidateAttribute
{
private int _Min = 0;
private int _Max = 0;
public StringLengthAttribute(int min, int max)
{
this._Min = min;
this._Max = max;
}
public override bool Validate(object objValue)
{
return objValue?.ToString()?.Length >= this._Min && objValue?.ToString()?.Length <= this._Max;
}
}
/// <summary>
/// 验证数字长度
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class LongAttribute : AbstractValidateAttribute
{
private long _Long = 0;
public LongAttribute(long LongLength)
{
this._Long = LongLength;
}
public override bool Validate(object objValue)
{
return objValue?.ToString()?.Length <= this._Long;
}
}
定义扩展方法,用于使用反射调用验证数据特性
public static class AttributeExtend
{
public static bool Validate<T>(this T t)
{
Type type = t.GetType();
// 获取类上的特性
foreach (var property in type.GetProperties())
{
if (property.IsDefined(typeof(AbstractValidateAttribute), true))
{
// 获取属性上的特性
object objValue = property.GetValue(t);
foreach (AbstractValidateAttribute attribute in property.GetCustomAttributes(true))
{
if (!attribute.Validate(objValue))
{
return false;
}
}
}
}
return true;
}
}
测试
public class Student
{
public int Id { get; set; }
[Required] // 验证是否为空
[StringLength(5, 10)] // 验证字符串长度
public string Name { get; set; }
[Required]
[Long(11)]
public long Phone { get; set; }
}
class Test
{
static void Main(string[] args)
{
Student student = new()
{
Id = 1,
Name = "张三asd",
Phone = 12345678901
};
if (student.Validate())
{
Console.WriteLine("验证通过");
}
else
{
Console.WriteLine("验证失败");
}
}
}
学习自视频:C#进阶学习之特性