目录
4、CallerFilePath、CallerLineNumber、CallerMemberName
涉及知识点: 特性 反射
一、前期准备
引入using:
using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
二、特性概念
特性: 他就是一个类, 继承Attribute,在特性类中,一般只配置 字段、属性、构造方法
使用场景:数据验证
特性三大步:
第一步 -- 定义特性 (编写一个类)
类需要继承Attribute,
并以Attribute为后缀
第二步 -- 标记 -- 标记时可省略Attribute后缀
第三步 -- 反射调用
三、特性案例
1、基础特性 -- 自定义
代码编写:
class NameAttribute : Attribute //第一步创建以Attribute结尾的类,并继承Attribute类
{
public string name; //字段
public int Id { set; get; } //属性
public NameAttribute(string name) //构造方法
{
this.name = name;
}
public NameAttribute(string name, int id) //构造方法
{
this.name = name;
this.Id = id;
}
}
class Student
{
[Name("小王", 1)] //第二步 标记特性,可省略Attribute后缀
public int Id { get; set; }
[Name("小白")]
public string Name { get; set; }
}
class AttributeInvoke
{
public static void Invoke<T>(T t) //第三步编写反射调用特性使用方法
{
//获取类
Type type = typeof(T);
//遍历类中的属性
foreach (PropertyInfo property in type.GetProperties())
{
//若该属性有NameAttribute标记
if (property.IsDefined(typeof(NameAttribute), true))
{
//获取NameAttribute特性
NameAttribute name = property.GetCustomAttribute<NameAttribute>();
Console.WriteLine(name.name);
Console.WriteLine(name.Id);
}
}
}
}
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
AttributeInvoke.Invoke(student);
Console.WriteLine("Hello World!");
}
}
结果显示:
2、特性实战 -- 自定义
第一步:创建抽象公共特性类
第二步:编写多个正常特性类,继承公共特性类
第三步:编写反射调用特性方法
第四步:标记,并调用特性方法,校验
代码编写:
//第一步: 创建抽象公共特性类
public abstract class CommonValidateAttribute : Attribute
{
public abstract bool Validate(object obj);
}
//第二步: 编写多个正常特性类,继承公共特性类
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class LengthAttribute : CommonValidateAttribute
{
public int Max;
public int Min;
public LengthAttribute(int max, int min)
{
Max = max;
Min = min;
}
public override bool Validate(object objValue)
{
return objValue != null &&
objValue.ToString().Length < Max &&
objValue.ToString().Length > Min;
}
}
public class NameLengthAttribute : CommonValidateAttribute
{
public int count;
public NameLengthAttribute(int count)
{
this.count = count;
}
public override bool Validate(object objValue)
{
return objValue.ToString().Length == count;
}
}
//第三步:编写反射调用特性方法
public class AttributeInvoke
{
public static bool Invoke<T>(T t)
{
Type type = typeof(T);
foreach (FieldInfo field in type.GetFields())
{
Object objValue = field.GetValue(t);
foreach (CommonValidateAttribute item in field.GetCustomAttributes(typeof(CommonValidateAttribute), true))
{
return item.Validate(objValue);
}
}
return false;
}
}
//第四步:标记,并调用特性方法,校验
public class Student
{
[NameLength(3)]
public string name;
[Length(15, 8)]
public long Phone;
}
internal class Program
{
static void Main(string[] args)
{
string information;
Student Tom = new Student()
{
name = "王小红",
Phone = 123456789
};
information = AttributeInvoke.Invoke(Tom) ? "数据正确" : "数据格式错误";
Console.WriteLine(information);
Student Jack = new Student()
{
name = "小白",
Phone = 123
};
information = AttributeInvoke.Invoke(Jack) ? "数据正确" : "数据格式错误";
Console.WriteLine(information);
}
}
结果显示:
3、常用特性类 -- 官方
1、ObsoleteAttribute
概念:
[Obsolete] -- 类已过时
-- 系统自动调用
-- 默认警告提示
代码编写:
internal class Program
{
static void Main(string[] args)
{
Student Tom = new Student()
{
id = 2, //绿色波浪线
name = "Tom", //绿色波浪线
phone = 15258545856, //红色波浪线
email = "2578395032@qq.com", //绿色波浪线
};
Console.WriteLine("Hello World!");
}
}
public class Student
{
[Obsolete] // 已过时(抛警告)
public int id;
[Obsolete("2022.12.10废弃")] //默认是false -- 推荐
public string name;
[Obsolete("不可用", true)] //调用时报红色波浪线错误 -- 编译不可以通过,错误
public long phone;
[Obsolete("已废弃", false)] //调用时报绿色波浪线警告 -- 编译可以通过,警告
public string email;
}
结果显示:
2、AttributeUsageAttribute
概念:
[AttributeUsage] -- 配置特性标记范围
代码编写:
//设置Student特性只能应用于类和方法上,默认 不允许多个特性,可查询特性的父类
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TeacherAttribute : Attribute
{
public TeacherAttribute() { }
}
[Teacher]
[Teacher] //报红,报错,不可标记多个特性
public class Student
{
[Teacher] //报红,报错,只能标记在类和方法上面
public string Name { get; set; }
}
3、ConditionalAttribute
概念:
[Conditional] -- 条件编译 -- 只可应用在方法和特性类上
-- 若定义,正常调用
-- 若未定义,则不被调用
代码编写:
#define teacherAttribute
//#define fun
[Conditional("teacherAttribute")]
public class TeacherAttribute : Attribute
{
public string name;
public TeacherAttribute(string name)
{
this.name = name;
}
}
[Teacher("学生")]
public class Student
{
[Conditional("teacherAttribute")]
public void Music() => Console.WriteLine("听音乐");
[Conditional("fun")]
public void Song() => Console.WriteLine("唱歌");
}
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
student.Music(); //fun 定义 -- 运行
student.Song(); //teacherAttribute 未定义 -- 不运行
//校验Teacher特性 -- fun 定义,运行
Type type = typeof(Student);
if (type.IsDefined(typeof(TeacherAttribute), true))
{
TeacherAttribute attribute = (TeacherAttribute)type.GetCustomAttribute(typeof(TeacherAttribute), true);
Console.WriteLine(attribute.name);
}
Console.WriteLine("Hello World!");
}
}
结果显示:
4、CallerFilePath、CallerLineNumber、CallerMemberName
概念:
只可用于方法的入参
[CallerFilePath] --文件路径
[CallerLineNumber] -- 代码行数
[CallerMemberName] -- 成员名称
代码编写:
//只可应用于参数
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
student.Music();
Console.WriteLine("Hello World!");
}
}
class Student
{
public void Music([CallerMemberName] string memberName = "",
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
Console.WriteLine("听音乐");
Console.WriteLine("memberName: " + memberName);
Console.WriteLine("filePath: " + filePath);
Console.WriteLine("lineNumber " + lineNumber);
}
}
结果显示:
5、DebuggerStopThrough
概念:
[DebuggerStopThrough] -- 调试时不进入此方法,方法内部正常调用
代码编写:
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
student.Music();
Console.WriteLine("Hello World!");
}
}
class Student
{
[DebuggerStepThrough] //调试时不进入此方法,方法内部正常调用
public void Music()
{
Console.WriteLine("听音乐");
}
}
6、RequiredAttribute
概念:
[Required] -- 属性不能为 ""
-- 一般应用于string类型上面,不建议放在int类型上面
代码编写:
internal class Program
{
static void Main(string[] args)
{
Student student = new Student();
Type type = typeof(Student);
foreach (PropertyInfo property in type.GetProperties())
{
object objValue = property.GetValue(student);
if (property.IsDefined(typeof(RequiredAttribute), true))
{
RequiredAttribute required = (RequiredAttribute)property.GetCustomAttribute(typeof(RequiredAttribute), true);
if (!required.IsValid(objValue))
{
Console.WriteLine($"{property.Name} 验证不通过");
}
}
}
Console.WriteLine("--" +student.Name);
Console.WriteLine("--" +student.Id);
Console.WriteLine("Hello World!");
}
}
class Student
{
[Required] //int一般不用这个特性
public int Id { get; set; }
[Required] //一般应用于string类型
public string Name { get; set; }
}
结果显示:
如有错误,烦请批评指正