C# 自定义特性(Attribute)+ 反射读取特性 +WinForm 自定义控件常用特性

发布时间:2026/7/5 14:12:31

C# 自定义特性(Attribute)+ 反射读取特性 +WinForm 自定义控件常用特性 一、核心概念1. 什么是特性特性Attribute是标记代码元素的描述信息类、方法、字段、属性。作用给代码附加额外元数据编译时标记、运行时通过反射读取实现扩展功能。系统自带特性Obsolete、Conditional本课重点自己定义特性 反射解析特性数据2. 自定义特性固定步骤必考背诵步骤1创建类继承 Attribute 基类规范类名以 Attribute 结尾步骤2添加 [AttributeUsage] 限制特性使用规则步骤3定义属性、构造函数接收参数步骤4将自定义特性标记在 类/方法 上步骤5通过反射 Type / MethodInfo 读取特性信息二、AttributeUsage 限制规则重点[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple true,Inherited false)]参数详解1. AttributeTargets限定特性可以标记在哪些位置Class标记类Method标记方法Field标记字段Property标记属性All所有位置2. AllowMultiple是否允许重复标记同一个元素true允许多次标记本案例 Test1 标记了两个 MyAttributefalse同一个位置只能标记一次3. Inherited是否允许子类继承该特性true子类继承父类特性false子类不继承本案例关闭继承三、自定义特性类完整代码解析//限制只能标记类、方法允许多次标记不允许继承 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple true,Inherited false)] internal class MyAttribute:Attribute { //自定义特性存储的字段信息 public string Version { get; set; } //版本号 public string Name { get; set; } //作者名称 public string Message { get; set; } //功能描述 public string CallTime { get; set; } //编写时间 //构造函数给特性赋值 public MyAttribute(string version, string name, string message, string callTime) { Version version; Name name; Message message; CallTime callTime; } }规范自定义特性必须继承 Attribute类名规范xxxAttribute构造函数用于接收标记时传入的参数四、标记特性使用特性1、标记在类上[My(1.0,Jack,入口类,2026-7-1)] internal class Program2、多次标记在方法上AllowMultipletrue 生效[MyAttribute(1.0, Jack, Test1方法, 2026-7-1)] [MyAttribute(2.0, Rose, Test1方法, 2026-7-2)] public static void Test1() { Console.WriteLine(Test1); }因为设置了AllowMultiple true同一个方法可以挂载多个特性五、反射读取特性完整流程核心考点完整四步流程必背第一步获取当前类的 Type 类型Type t1 typeof(Program);第二步通过Type获取指定方法的元数据 MethodInfoMethodInfo info t1.GetMethod(Test1);第三步获取该方法上所有自定义特性object[] attrs info.GetCustomAttributes(typeof(MyAttribute),false);第四步遍历读取特性中的自定义属性反射代码逐行解析//获取Program类的类型 Type t1 typeof(Program); //通过反射拿到Test1方法信息 MethodInfo info t1.GetMethod(Test1); //判空防止报错 if (info!null) { //反射调用方法 info.Invoke(null,null); } //获取该方法上所有 MyAttribute 特性 //参数2 false不向父类查找特性 object[] attrs info.GetCustomAttributes(typeof(MyAttribute),false); //遍历所有特性读取自定义数据 foreach (MyAttribute attr in attrs) { Console.WriteLine(attr.Name:attr.Message); }六、运行结果Test1Jack:Test1方法Rose:Test1方法七、重难点总结考试简答1、自定义特性必须满足什么条件必须继承 Attribute 类配合 AttributeUsage 声明使用范围。2、AllowMultiple 作用true 允许同一个位置多次标记同一个特性。3、Inherited 作用控制子类是否继承父类的特性。4、如何读取自定义特性通过反射 Type / MethodInfo 的 GetCustomAttributes 方法获取。八、高频易错点1、不加 AttributeUsage特性默认只能标记一次、不可继承、适用性窄2、多次标记特性必须开启 AllowMultiple true3、特性数据必须通过反射读取直接无法访问4、GetCustomAttributes 第二个参数 false 不搜索父类九、完整版可直接抄写代码MyAttributeusing System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _6自定义特性 { // 1自定义特性步骤 // 1 定义一个类继承于Attribute 类最好以Attribute单词进行结尾 // 2 通过AttributeUsage特性规划自定义特性的特点 // AttributeTargets.Clas 把特性放置到类的前面 // Method 把特性放置到方法的前面 // Field 把特性放置到字段的前面 //Property 把特性放置到属性的前面 //AllowMultiple 允许特性是否可以多次使用 //Inherited 是否能够被派生类进行继承 [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple true,Inherited false)] internal class MyAttribute:Attribute { public string Version { get; set; }// 版本 public string Name { get; set; } // 名称 public string Message { get; set; }// 描述信息 public string CallTime { get; set; } //时间 public MyAttribute(string version, string name, string message, string callTime) { Version version; Name name; Message message; CallTime callTime; } } }Programusing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace _6自定义特性 { [My(1.0,Jack,入口类,2026-7-1)] internal class Program { static void Main(string[] args) { //Test1(); //直接调用这个方法必须先保证这个方法存在 //引出反射获取特性等等信息 Type type typeof(int);//获取int的类型 Console.WriteLine(type); //System.Int32 Type t1 typeof(Program);//获取program类型 Console.WriteLine(t1); //_6自定义特性.Program MethodInfo info t1.GetMethod(Test1); //通过反射获取Test1方法 if (info!null) { info.Invoke(null,null);//调用方法 } //获取方法的特性集合 参数1 特性的的类型 参数2 写成false 不会去子类去搜索特性 object[] attrs info.GetCustomAttributes(typeof(MyAttribute),false); foreach (MyAttribute attr in attrs) { Console.WriteLine(attr.Name:attr.Message); } // 1 先获取的类的类型 Type t1 typeOf(program) // 2 再获取方法 MethodInfo info t1.GetMethod(Test1); // 3 再根据方法获取方法上特性 object[] attrs info.GetCustomAttributes(typeof(MyAttribute),false); // 4 遍历特性上每一个属性 } [MyAttribute(1.0, Jack, Test1方法, 2026-7-1)] [MyAttribute(2.0, Rose, Test1方法, 2026-7-2)] public static void Test1() { Console.WriteLine(Test1); } public static void Test2() { } } }WinForm 自定义控件常用特性一、课程知识点概述在 WinForm 开发中我们可以对自定义用户控件UserControl的公开属性添加系统内置特性。这类特性专门用于控制 Visual Studio 右侧【属性面板】的展示样式、分类、描述、默认值、废弃状态是规范自定义控件、封装通用组件的核心知识点。本节课包含两大核心内容1. 五大常用控件属性特性Browsable、Category、Description、DefaultValue、Obsolete2. 纯代码手写自定义控件无拖拽设计器 DesignerCategory 特性说明二、五大核心特性 逐一点精讲必考1、[Browsable(bool)] 可见性特性作用控制自定义属性是否在 VS 设计器的【属性面板】中显示。Browsable(true)默认值属性公开显示设计师可手动修改。Browsable(false)属性隐藏属性面板不可见仅后台代码可调用。2、[Category(分类名称)] 分类特性作用对自定义属性进行分组归类。系统自带分类外观、布局、行为、数据。可自定义任意分类名相同分类的属性会在面板中统一收纳整洁规整。案例Account 归为「佛得角」、Password 归为「阿根廷」。3、[Description(描述文本)] 注释特性作用鼠标悬浮在属性上时展示功能说明文字。用于标注属性用途提升控件可读性方便团队协作开发。4、[DefaultValue(默认值)] 默认值特性重点核心功能① 标记属性的初始默认值②视觉区分修改状态属性值 默认值 → 普通字体属性值被修改 → 字体自动加粗。注意仅为设计器视觉标记不会自动给属性赋值真正初始化赋值需要代码实现。5、[Obsolete(提示信息)] 废弃特性作用标记当前属性过时、不推荐使用。效果编译输出警告、属性面板标注废弃提示强制提示开发者更换新属性。三、可视化自定义控件代码解析UserControl1功能说明该控件为拖拽式自定义用户控件内置两个文本框封装 Account账号、Password密码两个公开属性属性与文本框双向绑定。完整代码逐行解析using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace _7_自定义控件常用的特性 { public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } //控制属性在属性面板显示 [Browsable(true)] //自定义属性分类 [Category(佛得角)] //属性功能描述 [Description(账号的内容)] //设置属性默认值区分是否被修改 [DefaultValue(佛得角)] //账号属性双向绑定textBox1文本 public string Account { get { return textBox1.Text; } set { textBox1.Text value; } } //多特性合并写法效果完全一致 [Description(密码),Category(阿根廷),DefaultValue(123),Obsolete(不建议使用此属性)] //密码属性双向绑定textBox2文本标记为废弃 public string Password { get { return textBox2.Text; } set { textBox2.Text value; } } } }代码核心逻辑1、属性get读取文本框内容对外暴露值2、属性set外部赋值同步修改文本框显示内容3、通过多特性组合完全自定义属性在设计器的展示效果。四、纯代码手写自定义控件解析UserLoin1、核心特性说明[DesignerCategory(Code)]作用标记当前控件为纯代码控件告知 VS 无需开启可视化拖拽设计器避免报错纯手写布局专用。本案例注释该特性可按需开启。2、手写控件原理1、自定义类继承 UserControl 用户控件基类2、手动声明 Label、TextBox、Button 等子控件3、重写 InitializeComponent 方法手动设置控件坐标、大小、文本、索引4、通过 Controls.Add() 将子控件挂载到自定义控件中5、SuspendLayout/ResumeLayout 优化批量加载控件性能。完整手写控件代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace _7_自定义控件常用的特性 { // 关键特性告诉VS这是纯代码类不是可拖拽设计界面 //[DesignerCategory(Code)] internal class UserLoin:UserControl { //手动声明所有子控件 private Label label1; private TextBox textBox1; private Label label2; private Button button1; private TextBox textBox2; public UserLoin() { InitializeComponent(); } //纯手写布局方法 private void InitializeComponent() { this.label1 new System.Windows.Forms.Label(); this.textBox1 new System.Windows.Forms.TextBox(); this.label2 new System.Windows.Forms.Label(); this.textBox2 new System.Windows.Forms.TextBox(); this.button1 new System.Windows.Forms.Button(); this.SuspendLayout(); // 账号Label this.label1.AutoSize true; this.label1.Location new System.Drawing.Point(97, 51); this.label1.Name label1; this.label1.Size new System.Drawing.Size(70, 24); this.label1.TabIndex 0; this.label1.Text 账号:; // 账号输入框 this.textBox1.Location new System.Drawing.Point(207, 51); this.textBox1.Name textBox1; this.textBox1.Size new System.Drawing.Size(244, 35); this.textBox1.TabIndex 1; // 密码Label this.label2.AutoSize true; this.label2.Location new System.Drawing.Point(97, 128); this.label2.Name label2; this.label2.Size new System.Drawing.Size(70, 24); this.label2.TabIndex 0; this.label2.Text 密码:; // 密码输入框 this.textBox2.Location new System.Drawing.Point(207, 125); this.textBox2.Name textBox2; this.textBox2.Size new System.Drawing.Size(244, 35); this.textBox2.TabIndex 1; // 登录按钮 this.button1.Location new System.Drawing.Point(207, 240); this.button1.Name button1; this.button1.Size new System.Drawing.Size(131, 52); this.button1.TabIndex 2; this.button1.Text 登录; this.button1.UseVisualStyleBackColor true; // 将所有子控件添加到自定义控件中 this.Controls.Add(this.button1); this.Controls.Add(this.textBox2); this.Controls.Add(this.label2); this.Controls.Add(this.textBox1); this.Controls.Add(this.label1); this.Name UCLogin; this.Size new System.Drawing.Size(585, 359); this.ResumeLayout(false); this.PerformLayout(); } } }五、特性组合使用规则1、多个特性可以分行书写也可以逗号同行书写效果完全一致2、所有控件特性仅在设计器界面生效不影响程序运行逻辑3、DefaultValue 只做视觉标记不会覆盖代码初始化值4、Obsolete 只产生编译警告不阻断程序运行。六、考试/作业 核心背诵总结1. Browsable控制属性面板是否显示自定义属性2. Category自定义属性分类规整设计器界面3. Description为属性添加悬浮功能注释4. DefaultValue设置默认值修改后字体加粗提示5. Obsolete标记属性废弃编译弹出警告6. DesignerCategory(Code)声明纯手写代码控件禁用可视化设计器

相关新闻