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)声明纯手写代码控件禁用可视化设计器

相关新闻

C++语言基础4:例程讲解(结合在QT的应用)

C++语言基础4:例程讲解(结合在QT的应用)

我们从最基础的语法、每个关键字 / 符号的含义、每一行的执行逻辑逐句拆解&#xff0c;全程用新手能理解的表述&#xff0c;你可以对着代码一行一行看。例程如下&#xff1a;void TemperatureBar::update_data(int base_address, const QVector<quint16> &value) {Q_…

2026/7/5 14:12:32阅读更多 →
B11:AI 时代怎么跨部门协作?我用 4 步说服了销售、HR、IT 一起推 AI

B11:AI 时代怎么跨部门协作?我用 4 步说服了销售、HR、IT 一起推 AI

文章目录 B11:AI 时代怎么跨部门协作?我用 4 步说服了销售、HR、IT 一起推 AI 🎯 开篇:我做了一个 AI 工具,演示给销售总监看,他说了一句话 一、那天晚上,我想通了一件事 二、AI 时代,跨部门协作为什么变难了? 2.1 第一个难:AI 是"全公司的事",不是"…

2026/7/5 14:07:32阅读更多 →
Leetcode新动循环嵌套之数组异或操作、好数对的数目、统计好三元组

Leetcode新动循环嵌套之数组异或操作、好数对的数目、统计好三元组

1486.数组异或操作class Solution:def xorOperation(self, n: int, start: int) -> int:nums []for i in range(n):nums.append(start 2*i)resultnums[0]for i in range(1,n):result ^ nums[i]return result1512.好数对的数目class Solution:def numIdenticalPairs(self,…

2026/7/5 14:07:32阅读更多 →
F3闪存检测工具:5分钟识别扩容盘欺诈的完整指南

F3闪存检测工具:5分钟识别扩容盘欺诈的完整指南

F3闪存检测工具&#xff1a;5分钟识别扩容盘欺诈的完整指南 【免费下载链接】f3 F3 - Fight Flash Fraud 项目地址: https://gitcode.com/gh_mirrors/f3/f3 在数字时代&#xff0c;数据安全是每个人的首要关切。你是否遇到过新买的U盘价格异常便宜&#xff0c;但存储重要…

2026/7/5 15:22:44阅读更多 →
【Ansible】(十四)流程控制与异常处理

【Ansible】(十四)流程控制与异常处理

目录 一、前言 二、基础错误处理机制 1. 忽略任务错误 2. 强制执行 Handler 三、自定义任务执行状态 1. 自定义失败条件 failed_when 2. 自定义变更状态 changed_when 四、高级异常处理&#xff1a;Block、Rescue、Always 五、知识点总结问答 1. ignore_errors 的作用…

2026/7/5 15:22:44阅读更多 →
流放之路2构建规划终极指南:用Path of Building PoE2告别盲目配装

流放之路2构建规划终极指南:用Path of Building PoE2告别盲目配装

流放之路2构建规划终极指南&#xff1a;用Path of Building PoE2告别盲目配装 【免费下载链接】PathOfBuilding-PoE2 项目地址: https://gitcode.com/GitHub_Trending/pa/PathOfBuilding-PoE2 还在为《流放之路2》复杂的角色构建系统感到头疼吗&#xff1f;每次花费数小…

2026/7/5 15:22:44阅读更多 →
小学期第二周记录

小学期第二周记录

1.单电源供电的二阶低通滤波器2.功率放大器3.本周学习了在嘉立创上画发射部分的原理图&#xff08;如下图&#xff09;&#xff0c;并且完善了上周电路。&#xff08;注&#xff1a;该原理图不完全正确&#xff0c;在后续第六周的记录里已改正&#xff0c;改正后如下图&#xf…

2026/7/5 15:22:44阅读更多 →
Python OpenCV 二维傅里叶变换实战:5种经典图像频谱图生成与解读

Python OpenCV 二维傅里叶变换实战:5种经典图像频谱图生成与解读

Python OpenCV 二维傅里叶变换实战&#xff1a;5种经典图像频谱图生成与解读频域分析是图像处理中不可或缺的技术手段&#xff0c;而二维傅里叶变换则是打开频域大门的钥匙。不同于数学教材中复杂的公式推导&#xff0c;本文将带您用Python和OpenCV进行实战演练&#xff0c;通过…

2026/7/5 15:22:44阅读更多 →
SARSteer: Safeguarding Large Audio Language Models via Safe-Ablated Refusal Steering

SARSteer: Safeguarding Large Audio Language Models via Safe-Ablated Refusal Steering

文章核心总结与翻译 一、主要内容 本文聚焦大型音频语言模型(LALMs)的安全对齐问题,针对现有LLM和LVLM安全防御方法直接迁移至LALMs时存在的两大缺陷(音频输入下基于LLM的引导失效、基于提示的防御导致良性查询过度拒绝),提出了首个推理时防御框架SARSteer(Safe-Ablat…

2026/7/5 15:17:44阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述&#xff1a;从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目&#xff0c;叫 skills4/skills &#xff0c;它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景&#xff1a;一个旨在展示或教授某种技能的仓库&#xff0c;本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示&#xff1a;因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战&#xff1a;从“黑箱预测”到“可信推理”2026年6月&#xff0c;第7届机器学习与趋势国际会议&#xff08;MLT 2026&#xff09;将在悉尼召开。会议议程中&#xff0c;“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时&#xff0c;通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中&#xff0c;是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述&#xff1a;从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目&#xff0c;叫 skills4/skills &#xff0c;它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景&#xff1a;一个旨在展示或教授某种技能的仓库&#xff0c;本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示&#xff1a;因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战&#xff1a;从“黑箱预测”到“可信推理”2026年6月&#xff0c;第7届机器学习与趋势国际会议&#xff08;MLT 2026&#xff09;将在悉尼召开。会议议程中&#xff0c;“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时&#xff0c;通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中&#xff0c;是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时&#xff0c;发现推理速度只有可怜的 1-2 FPS&#xff0c;而别人的演示视频却能跑到 30 FPS 以上&#xff0c;那么问题很可能不在模型本身&#xff0c;而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后&#xff0c;会直接使用官方示例…

2026/7/5 1:30:27阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一&#xff1a;为什么你需要了解 Coze 和 Dify&#xff1f;如果你对 AI 应用开发感兴趣&#xff0c;但一看到“大模型”、“智能体”、“工作流”这些词就头疼&#xff0c;觉得门槛太高&#xff0c;那这篇文章就是为你准备的。很多开发者&#xff0c;包括我自己&#…

2026/7/5 3:48:10阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会&#xff1a;配图一直是个让人头疼的问题。2026年&#xff0c;AI生图工具已经非常成熟了&#xff0c;但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1&#xff1a;速度之王2026年6月11日&#xff0c…

2026/7/5 3:48:09阅读更多 →