C#中的特性 Attribute

特性:本质就是一个类,且必须继承至Attribute类
使用场景:(框架,类,方法,属性,字段,参数,返回值....)上面,Attribute通过的一些方法,比如:字段有没有定义特性,用来做判断。
命名规范:【public class 特性名Attribute : Attribute】  定义时Attribute不能实例,使用特性时可以省略只写特性名【特性名Attribute】或【特性名】
特性简单的四个步骤:1.定义---2.使用---3.定义类:通过反射查找到这个特性---4.调用:通过定义的查找特性类去调用。
特性配置:【AttributeUsage(参数1:可以放在方法和类上面默认类等等。参数2:是否可以多重定义特性默认false。参数3:是否可以被继承,默认true。)】

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class TableAttribute : Attribute //1、定义特性:一个特性就是一个类,特性上面也能加特性
{
    public string tname { get; set; }
    public TableAttribute() { }
    public TableAttribute(string str) { this.tname = str; }
}

//2、使用特性-----------------------------------------------------------------------------
[Serializable]//系统特性,表示可以当前类被实例化
[Table]//自定义特性
[Table("改表名")]//多重属性定义指AttributeUsage参数2:AllowMultiple可以所以多个构造方法
public class Student
{
    [Table]//参数1配置在方法上面也能使用
    public void cc() { }
}
public class ABC : Student { } //当AttributeUsage参数3Inherited改为false,那么也就是说,Student里的特性在ABC里不起作用。

第三步:查找-------第四步:调用,也就是验证字段是否符号要求。相当于约束。

Student stu = new Student();
string str = CustomAttribute.GetTableAttribute(stu);//4.调用
Console.WriteLine(str);//获取到[Table("改表名")]里的字符串参数:改表名

public class CustomAttribute //3.定义一个类专门用来查找特性
{ 
    public static string GetTableAttribute<T>(T node) where T:class //约束泛型只能传引用类型
    { 
        Type type = typeof(T);//typeof获取到对象名的数据类型
        if (type.IsDefined(typeof(TableAttribute), true))//帮你查找看看有没有定义这个特性,第二个参数:是否去找他的派生类,也就是子类中找
        { 
            var attribute = type.GetCustomAttributes(typeof(TableAttribute), true);//获取到这个类
            return ((TableAttribute)attribute[1]).tname;//上面使用了两个特性,第一个是无参构造,我需要的是第二个值。获取的是obj类型需要强制转换为需要显示的值。
        }
        else
        {
            return type.Name;
        }
    }
}

系统自带的特性

using System.ComponentModel.DataAnnotations;//系统特性需要引用

public class Student
{
    [Key]//主键:如果字段名是id,默认可以不写,如果是usersid这样就认不到必须定义主键。
    public int Id { get; set; }

    [Display(Name ="姓名")]//显示字段别名
    [Required]//不能为空
    [StringLength(maximumLength:50,MinimumLength =6)]//字符串长度
    [EmailAddress]//识别邮箱格式
    public string Name { get; set; }
}

自定义特性

using System.Reflection;//反射命名空间
using System.Text.RegularExpressions;//正则表达式命名空间

Student stu = new Student() { Id = 1,Name = "dss111@qq.com"};
var res = CustomAttribute.validate(stu);
Console.WriteLine(res);
CustomAttribute.GetStrNameAttribute(stu);//获取字符串的方法


//3.创建一个类专门查找特性的方法---------------------------------------------------
public class CustomAttribute
{
    public static bool validate<T>(T t)
    {
        PropertyInfo[] propertyinfo = t.GetType().GetProperties();//类的成员要通过反射获取,所有属性和特性使用是数组。
        foreach (var property in propertyinfo)
        {
            if (property.IsDefined(typeof(characteristicAttribute), true))
            {
                var attributes = property.GetCustomAttributes(typeof(characteristicAttribute), true);
                foreach (var item in attributes)
                {
                    characteristicAttribute attribute = item as characteristicAttribute;//类型转换,为空不报错,返回null
                    if (!attribute.IsValidate(property.GetValue(t))) return false;
                }
            }
        }
        return true;
    }
    //专门获取字符串的【取别名】
    public static void GetStrNameAttribute<T>(T node) where T : class //约束泛型只能传引用类型
    {
        Type type = typeof(T);//获取对象的数据类型。
        foreach (var property in type.GetProperties())//GetProperties通过反射获取到类的成员
        {
            if (property.IsDefined(typeof(StringNameAttribute), true))
            {
                var attribute = property.GetCustomAttributes(typeof(StringNameAttribute), true);//获取特性内容
                //return ((StringNameAttribute)attribute[0]).tname;//上面使用了两个特性,第一个是无参构造,我需要的是第二个值。获取的是obj类型需要强制转换为需要显示的值。
            
                Console.WriteLine(((StringNameAttribute)attribute[0]).tname+":" + property.Name+":"+ property.GetValue(node));
            }
        }
       // return type.Name;
    }
}

public class Student
{
    [Display("编号")]//显示字段别名
    [Key]//主键:如果字段名是id,默认可以不写,如果是usersid这样就认不到必须定义主键。
    public int Id { get; set; }
    [Display("姓名")]//显示字段别名
    [Required]//不能为空
    [StringLength(50,6)]//字符串长度
    [EmailAddress]//识别邮箱格式
    public string Name { get; set; }
}

//1.定义特性-----------------------------------------------------------------
abstract class characteristicAttribute : Attribute 
{
    public abstract bool IsValidate(object dataValue);
}
class StringNameAttribute : Attribute //获取字符串的一个公共特性
{
    public string tname { get; set; }
    public int i { get; set; }//多字段不写了,原理都差不多
    public StringNameAttribute(string str) { this.tname = str; }
}
//主键
class KeyAttribute : characteristicAttribute
{
    public bool IsPrimaryKey { get; set; } = true;
    public override bool IsValidate(object dataValue) { return IsPrimaryKey; }
}
//重新命名,取别名
class DisplayAttribute : StringNameAttribute
{  
    public DisplayAttribute(string str) : base(str) {  } //把参数传给父类构造方法去执行
    public DisplayAttribute(string str,int i) : base(str) {  }
}
//非空验证
class RequiredAttribute : characteristicAttribute
{
    public override bool IsValidate(object dataValue) 
    {
        return dataValue != null && dataValue.ToString().Length != 0;
    }
}
//字符串长度
class StringLengthAttribute : characteristicAttribute 
{
    public int maximumLength { get; set; }//最大长度
    public int MinimumLength { get; set; }//最小长度
    public StringLengthAttribute(int max, int min)
    {
        maximumLength = max;
        MinimumLength = min;
    }

    public override bool IsValidate(object dataValue)
    {
        return maximumLength >= dataValue.ToString().Length && dataValue.ToString().Length >= MinimumLength;
    }
}

//验证邮箱格式
class EmailAddressAttribute : characteristicAttribute
{
    public override bool IsValidate(object dataValue) 
    {
        //using System.Text.RegularExpressions;//正则表达式命名空间
        Regex regex = new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
        return regex.IsMatch(dataValue.ToString());//字符串是否一样 
    }
}

 

posted @ 2022-10-31 04:09  Akai_啊凯  阅读(146)  评论(0编辑  收藏  举报