第十一讲 特性
特性必须以Attribute结尾
特性: 就是我们自己定义的修饰符,这种修饰符可可以放到被修饰的对象上面 (特性的本质是一个类)
特性可以在修饰目标上面额外的扩展信息和行为,对修饰目标没有任何影响
定义: 自定义一个普特雷,继承Attribute就可以啦
问题: 我们给方法和属性写注释,对目标也没有影响,那特性和注释有什么区别
注释:是给开发者用的,是对源码的说明,编译是不参与的
特性:是源码的一部分,编译的时候,会放到元数据中,程序运行时我们可以动态得到,并且可以提取到这些信息后做相关的处理
vs:编译原理 写c#代码--->便是成exe/dll文件(IL)(这一步编译的是C#的文件,不能被机器识别"是微软的中间语言")---->CLR(JIT)(被C#文件编译成机器码)----->编译成机器码(10101010)
特性的位置是在: CLR的编译的IL(部分)+元数据
特性的作用: 1:)增加标识 2:)注入信息
AttributeUSage: 修饰特性的特性,主要说明这个特性在哪里使用
特性可以有多个构造方法,.
特性可以添加方法
并且特性可以继承
用属性实现一个数据的校验实例
特性定义类:
namespace ConsoleApplication15
{
/// <summary>
/// 声明一个统一的校验抽象特性
/// 特性也是一个类, 所有有类的基本特征,可以继承,抽象
/// </summary>
public abstract class BasAttribute : Attribute
{
public string Msg { get; set; }
public BasAttribute(string msg)
{
this.Msg = msg;
}
public abstract bool CheckData(object obj);
}
/// <summary>
/// 标记注释
/// </summary>
public class DisAttribute : Attribute
{
public string DisName { get; set; }
/// <summary>
/// 属性利用构造函数来初始化,传递值,可以有多个构造函数
/// </summary>
/// <param name="disName"></param>
public DisAttribute(string disName)
{
this.DisName = disName;
}
}
/// <summary>
/// 非空特性判断
/// </summary>
public class IsNullAttribute : BasAttribute
{
public IsNullAttribute(string msg) : base(msg) { }
public override bool CheckData(object obj)
{
return obj != null && obj.ToString().Length > 0;
}
}
/// <summary>
/// 取值范围判断
/// </summary>
public class RangeAttribute:BasAttribute
{
public RangeAttribute(string msg) : base(msg) { }
public int Max { get; set; }
public int Min { get; set; }
public RangeAttribute(int min, int max,string msg)
: base(msg)
{
this.Max = max;
this.Min = min;
}
public override bool CheckData(object obj)
{
return this.Min < (int)obj && (int)obj < this.Max;
}
}
}
特性使用类:
namespace ConsoleApplication15
{
public class StruntModles
{
[IsNull("字段不能为空")]
public string UserName { get; set; }
[Range(20,50,"数字超过了取值返回")]
public int Age { get; set; }
public string DisMsg { get; set; }
}
}
校验特性类:
namespace ConsoleApplication15
{
public class DataAttributeCheck
{
public static RetuenModles Check<T>(T t)
{
RetuenModles mode = new RetuenModles();
//获取传递的数据的 type(里面包含了类的所有信息)
Type type = t.GetType();
//获取共有的属性
PropertyInfo[] propers = type.GetProperties();
foreach (PropertyInfo prore in propers)
{
//找到属性上面的特性
var attributes = prore.GetCustomAttributes(typeof(BasAttribute), true);
foreach(var attr in attributes)
{
BasAttribute baattr = attr as BasAttribute;
if(!baattr.CheckData(prore.GetValue(t,null)))
{
mode.IsTrue = false;
mode.Msg = prore.Name + "属性:" + baattr.Msg;
return mode;
}
}
}
mode.IsTrue = true;
mode.Msg = "校验成功";
return mode;
}
}
}
校验结果返回类:
namespace ConsoleApplication15
{
/// <summary>
/// 校验返回数据的Mode
///
/// </summary>
public class RetuenModles
{
public bool IsTrue{get;set;}
public string Msg { get; set; }
}
}
使用方法:
namespace ConsoleApplication15
{
class Program
{
static void Main(string[] args)
{
var mode = new StruntModles() { UserName = "zzl", Age = 17, DisMsg = "校验" };
RetuenModles md = DataAttributeCheck.Check<StruntModles>(mode);
Console.WriteLine("校验数据是否通过:" +md.IsTrue);
Console.WriteLine(md.Msg);
Console.ReadKey();
}
}
}