C#中特性(Attribute)的使用

解读:首先特性是一个类,它继承于Attribute。它对程序中的元素进行标注,如类型、字段、方法和属性等。

Attribute是程序代码的一部分,它不会被编译器丢弃,而且还会被编译器编译进程序集(Assembly)的元数据(Metadata)里。

新建一个CustomAttribute的类:

public class CustomAttribute:Attribute
{
    public CustomAttribute()
    {
        Console.WriteLine(nameof(CustomAttribute));
    }
}

在建一个Department类,在类上面加上Custom特性:

[Custom]
public class Department
{
    public Guid id { get; set; }
    public string name { get; set; }

    public void GetName()
    {
        Console.WriteLine(nameof(GetName));
    }
}

我们反编译Department类查看一下

特性添加后,编译会在元素内部产生IL,在metadata中会有记录(这样就可以通过反射操作它),但是没办法直接使用。

无论是在类或类中的元素上面添加特性,反编译时会看看特性会在类或类中的元素里面生成一个构造(.ctor())。

特性的多重修饰

 

AllowMultiple=true是指在一个(元素)类中可以多重修饰
AttributeTargets.All表示任何元素类型都可以用其修饰

 

特性其它语法:

 新建一个Student的类,给这个类加上CustomAttribute的特性

[CustomAttribute(123, details = "call")]
public class Students
{
    public int id { get; set; }
    
[CustomAttribute]
public string name { get; set; }
    [Custom]
    [return: Custom]
    public void Method([Custom] string name)
    {
      Console.WriteLine("success");
    }
}

再建一个Manage类,找出Students类上的特性,并进行调用操作等...

public static class Manage
{
    public static void show(Students students)
    {
        //获取类型
        Type type = typeof(Students);
        //查找是否有CustomAttribute这个特性
        if (type.IsDefined(typeof(CustomAttribute), true))
        {
            //实例化得到一个CustomAttribute类型
            //通过反射创建对象
            CustomAttribute attribute = (CustomAttribute)type.GetCustomAttribute(typeof(CustomAttribute), true);
            Console.WriteLine($"{attribute.details}");
//调用方法 attribute.show(); } } }

调用:

Students students = new Students();
Manage.show(students);

找出Students类中属性上的的特性

//name为字段名
PropertyInfo prop = type.GetProperty("name"); if (prop.IsDefined(typeof(CustomAttribute), true)) { //实例化得到一个CustomAttribute类型 //通过反射创建对象 CustomAttribute attribute = (CustomAttribute)prop.GetCustomAttribute(typeof(CustomAttribute), true); Console.WriteLine($"{attribute.details}"); attribute.show(); }

找出Students类中方法上的特性

//Method为方法名
MethodInfo method = type.GetMethod("Method"); if (method.IsDefined(typeof(CustomAttribute), true)) { //实例化得到一个CustomAttribute类型 //通过反射创建对象 CustomAttribute attribute = (CustomAttribute)method.GetCustomAttribute(typeof(CustomAttribute), true); Console.WriteLine($"{attribute.details}"); attribute.show(); }

找出Students类中方法中参数的特性

ParameterInfo parameter = method.GetParameters()[0];
if (parameter.IsDefined(typeof(CustomAttribute), true))
{
    //实例化得到一个CustomAttribute类型
    //通过反射创建对象
    CustomAttribute attribute = (CustomAttribute)parameter.GetCustomAttribute(typeof(CustomAttribute), true);
    Console.WriteLine($"{attribute.details}");
    attribute.show();
}

找出Students类中方法中返回值的特性

ParameterInfo returnParameter = method.ReturnParameter;
if (returnParameter.IsDefined(typeof(CustomAttribute), true))
{
    //实例化得到一个CustomAttribute类型
    //通过反射创建对象
    CustomAttribute attribute = (CustomAttribute)returnParameter.GetCustomAttribute(typeof(CustomAttribute), true);
    Console.WriteLine($"{attribute.details}");
    attribute.show();
}

通过上面的代码可以知道,特性可以在没有破坏封装的前提下,可以加点额外的信息和行为,充当补充类使用。

通过特性操作枚举数据,获取枚举字段上的描述信息

public class RemarkExtension
{
    /// <summary>
    /// 用户状态
    /// </summary>
    public enum UserState
    {
        [Remark("正常")]
        Normal = 0,//正常  左边字段名称,右边是值
        [Remark("冻结")]
        Frozen = 1,//冻结
        [Remark("删除")]
        Deleted = 2//删除
    }

    public class RemarkAttribute : Attribute
    {
        public RemarkAttribute(string remarks)
        {
            this._remarks = remarks;
        }
        public string _remarks;

        public string GetRemark()
        {
            return this._remarks;
        }
    }
}

public static class RemarksExtension
{
//扩展方法是静态类中的静态方法,在参数类型前加一个this.可以通过这个类型实例直接调用这个方法。
public static string GetRemarks(this Enum value) { //获取类型 Type type = value.GetType(); //找到这个字段 FieldInfo fieldInto = type.GetField(value.ToString()); //这个字段上面是否有RemarkAttribute属性 if (fieldInto.IsDefined(typeof(RemarkAttribute), true)) {
//实例化,将参数赋值给_remarks RemarkAttribute attribute
= (RemarkAttribute)fieldInto.GetCustomAttribute(typeof(RemarkAttribute)); //取值
return attribute.GetRemark(); } else { return value.ToString(); } } }

调用:

UserState userState = UserState.Normal;
Console.WriteLine(userState.GetRemarks());
Console.WriteLine(UserState.Frozen.GetRemarks());
Console.WriteLine(UserState.Deleted.GetRemarks());

 通过特性做数据校验

public static class ValidataExtension
{
    /// <summary>
    /// 一个object的扩展方法
    /// </summary>
    /// <param name="o"></param>
    /// <returns></returns>
    public static bool Validata(this object o)
    {
        Type type = o.GetType();
        //循环对象里的所有属性
        foreach (var prop in type.GetProperties())
        {
            //查看属性上面是否有LongAttribute这个特性
            //if (prop.IsDefined(typeof(LongAttribute), true))
            //{
            //    LongAttribute attribute = (LongAttribute)prop.GetCustomAttribute(typeof(LongAttribute), true);
            //    if (!attribute.Validata(prop.GetValue(o)))
            //    {
            //        return false;
            //    }
            //}

            //查看属性上面是否有LengAttribute这个特性
            //if (prop.IsDefined(typeof(LengAttribute), true))
            //{
            //    LengAttribute attribute = (LengAttribute)prop.GetCustomAttribute(typeof(LengAttribute), true);
            //    if (!attribute.Validata(prop.GetValue(o)))
            //    {
            //        return false;
            //    }
            //}

            if (prop.IsDefined(typeof(AbstractValidataAttribute), true))
            {
                //GetCustomAttributes是多个
                //GetCustomAttribute是单个
                object[] attributeArray = prop.GetCustomAttributes(typeof(AbstractValidataAttribute), true);
                foreach (AbstractValidataAttribute attribute in attributeArray)
                {
                    if (!attribute.Validata(prop.GetValue(o)))
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }
}

/// <summary>
/// 声明一个抽象类,其它的特性类继承于它
/// </summary>
public abstract class AbstractValidataAttribute : Attribute
{
    public abstract bool Validata(object value);
}


/// <summary>
/// 判断string数据的长度
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
// public class LengAttribute : Attribute
public class LengAttribute : AbstractValidataAttribute
{
    private long _min = 0;
    private long _max = 0;
    public LengAttribute(long min, long max)
    {
        this._max = max;
        this._min = min;
    }

    /// <summary>
    /// 重写父类Validata方法
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public override bool Validata(object value)
    {
        if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            int length = value.ToString().Length;
            if (length > this._min && length < this._max)
            {
                return true;
            }
        }
        return false;
    }
}

//public class LongAttribute : Attribute
/// <summary>
/// 判断数据的范围
/// </summary>
public class LongAttribute : AbstractValidataAttribute
{
    private long _min = 0;
    private long _max = 0;
    public LongAttribute(long min, long max)
    {
        this._max = max;
        this._min = min;
    }

    public override bool Validata(object value)
    {
        if (value != null && !string.IsNullOrWhiteSpace(value.ToString()))
        {
            //判断是否为long类型,如果是直接给到result
            if (long.TryParse(value.ToString(), out long result))
            {
                if (result > this._min && result < this._max)
                {
                    return true;
                }
            }
        }
        return false;
    }
}
public class Students
{
    public int id { get; set; }

    [LengAttribute(5, 10)]
    public string name { get; set; }

    [LengAttribute(10, 20)]
    public string Acount { get; set; }

    [LongAttribute(10001, 999999999999)]
    public long QQ { get; set; }

    public long _QQ2 = 0;

    public long QQ2
    {
        get
        {
            return this._QQ2;
        }
        set
        {
            if (value > 10001 && value < 99999999999)
            {
                _QQ2 = value;
            }
            else
            {
                throw new Exception("Data error!");
            }
        }
    }
}

调用:

Students students = new Students();
students.study();
students.name = "JavaJava";
students.QQ = 999999;
students.Acount = "c#c#c#c#c#c#c#c#";
students.Validata();
posted @ 2020-06-27 18:01  江北、  阅读(1994)  评论(0编辑  收藏  举报