29.Winfrom —— 复习委托、事件、特性、反射

📅 2026/7/2 2:04:45
29.Winfrom —— 复习委托、事件、特性、反射
目录一、委托Delegate1. 核心概念2. 使用四步流程3. 完整 Demo 代码4. 委托两种典型使用场景二、事件Event1. 委托与事件关系2. 事件标准开发流程3. 内置标准事件EventHandlerProgram 入口 DemoWinForm 自定义按钮事件订阅示例4. 发布器类规则总结三、委托嵌套与回调思想1. 委托嵌套 多层方法包装2. 回调核心用法方法接收委托参数完整 Demo四、系统内置特性Attribute4.1 ConditionalAttribute 条件编译特性4.2 Obsolete 废弃标记特性五、自定义特性 反射读取特性1. 自定义特性开发步骤5.1 自定义特性类 MyAttribute.cs5.2 反射读取特性 Demo Program.cs读取特性固定流程六、WinForm 自定义控件专用设计器特性常用设计器特性说明Demo UserControl1.cs七、反射Reflection1. 反射核心作用2. 反射完整操作流程7.1 主程序反射代码7.2 外部类库 ClassLibrary1.dll 源码八、整体知识点串联总结一、委托Delegate1. 核心概念委托本质是方法的载体 / 类型安全的函数指针可以存储、传递、批量执行多个方法支持多播绑定多个方法、Lambda、匿名委托。2. 使用四步流程定义委托类型规定方法返回值、参数列表编写匹配签名的静态 / 实例方法委托实例化4 种写法调用委托执行绑定的方法3. 完整 Demo 代码using System; namespace _1委托复习 { internal class Program { // 1.定义委托类型返回int参数(int,string) public delegate int MyDelegate(int a, string b); static void Main(string[] args) { // 方式1 new关键字实例化 MyDelegate m1 new MyDelegate(F1); // 三种调用方式 F1(10, 11);// 直接调用方法 m1(10,11); // 委托简写调用 m1.Invoke(10, 11); // 标准Invoke调用 m1?.Invoke(10, 11);// 空安全调用推荐 Console.WriteLine(--------------------); // 方式2 多播委托 追加方法 m1 F2; m1(1, ss); Console.WriteLine(--------------------); // 方式3 Lambda表达式绑定 m1 (a, b) { Console.WriteLine(lambda表达式); return 10; }; m1(1, ss); // 方式4 匿名委托绑定 m1 delegate (int a, string b) { Console.WriteLine(匿名委托); return 10; }; m1(1, ss); } // 与委托签名匹配的方法 public static int F1(int a,string b) { Console.WriteLine(F1函数); return 10; } public static int F2(int a, string b) { Console.WriteLine(F2函数); return 10; } } }4. 委托两种典型使用场景多播场景一个委托绑定 N 个方法一次调用批量执行追加、-移除回调场景方法接收委托参数外部传入不同逻辑实现同一方法多种行为二、事件Event1. 委托与事件关系事件是封装后的委托实例做了访问权限限制外部只能订阅、-取消订阅不能直接赋值、不能在类外部主动调用委托无封装任意地方可赋值、直接执行事件用于界面消息、消息通知。2. 事件标准开发流程定义委托或使用系统自带EventHandler在发布器类中声明event 委托类型 事件名;发布器内部写触发方法判断事件不为 null 后执行外部类订阅事件实例.事件 回调方法3. 内置标准事件EventHandler系统自带委托public delegate void EventHandler(object sender, EventArgs e)所有 WinForm 原生控件点击事件都使用该类型。Program 入口 Demousing System; using System.Windows.Forms; namespace _2事件 { internal static class Program { // 系统内置事件 public static event EventHandler MyEvent; // 自定义委托 public delegate void MyDelete(); // 自定义事件 public static event MyDelete my; [STAThread] static void Main() { // 订阅内置事件 MyEvent (a, b) { Console.WriteLine(内置的事件); }; MyEvent(null, null); // 订阅自定义事件 my Program_my; my(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } private static void Program_my() { Console.WriteLine(Program_my); } } }WinForm 自定义按钮事件订阅示例using System; using System.Windows.Forms; namespace _2事件 { // 自定义事件委托 public delegate void MyEventHandle(object o, EventArgs e); public partial class Form1 : Form { public Form1() { InitializeComponent(); // 原生按钮事件订阅 button1.Click button1_Click; // 自定义控件事件订阅 myButton1.MyClick MyButton1_MyClick; myButton1.Click myButton1.myButton_Click; } private void MyButton1_MyClick(object o, EventArgs e) { MessageBox.Show(MyButton自定义事件触发); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show(系统内置Button点击事件); } } }4. 发布器类规则总结持有event事件成员内部提供触发逻辑仅本类能调用事件外部仅可订阅 / 取消订阅保证消息安全分发三、委托嵌套与回调思想1. 委托嵌套 多层方法包装多层委托互相调用形成调用栈可以统一在方法执行前后插入前置 / 后置逻辑AOP 雏形。2. 回调核心用法方法接收委托参数将逻辑通过委托传入方法同一函数实现多种业务逻辑扩展性极强。完整 Demousing System; namespace _3委托嵌套 { internal class Program { public delegate void Del1(); public delegate string Del2(); static void Main(string[] args) { // 多层嵌套委托 Del1 del1 () { Console.WriteLine(SayHello执行前); SayHello(); Console.WriteLine(SayHello执行后); }; Del1 del2 () { Console.WriteLine(del1执行前); del1.Invoke(); Console.WriteLine(del1执行后); }; Del1 del3 () { Console.WriteLine(del2执行前); del2.Invoke(); Console.WriteLine(del2执行后); }; del3(); // 普通多层方法对比 Method3(); // 委托回调同一个方法传入不同逻辑 Console.WriteLine(SayHello(() { return 说中国话; })); Console.WriteLine(SayHello(() { return 说日本话; })); Console.WriteLine(SayHello(() { return 说美国话; })); } public static void SayHello() { Console.WriteLine(SayHello执行); } // 接收Func委托作为回调参数 public static string SayHello(Funcstring d) { return d.Invoke(); } // 普通方法嵌套 public static void Method1() Console.WriteLine(Method1执行); public static void Method2() { Console.WriteLine(Method1执行前); Method1(); Console.WriteLine(Method1执行后); } public static void Method3() { Console.WriteLine(Method2执行前); Method2(); Console.WriteLine(Method2执行后); } } }四、系统内置特性Attribute特性是挂载在类、方法、属性上的标记通过反射读取用于控制编译、IDE 显示、程序逻辑。4.1 ConditionalAttribute 条件编译特性作用只有定义对应编译符号时该方法才会被编译进程序未定义符号时所有调用代码直接删除。// #define Debug 开启符号#undef Debug关闭符号 #undef Debug using System; using System.Diagnostics; namespace _4_ConditionalAttribute条件特性 { internal class Program { static void Main(string[] args) { T1(); } // 仅定义Debug符号时T1方法生效 [Conditional(Debug)] public static void T1() { Console.WriteLine(1111); } } }4.2 Obsolete 废弃标记特性作用标记方法 / 类过时提示开发者替换第二个参数控制警告 / 编译报错。参数 1废弃提示文本参数 2false 编译器警告true 直接编译报错using System; namespace _5Obsolete废弃特性 { internal class Program { static void Main(string[] args) { Test1(); Test2(); } [Obsolete(Test1已废弃请使用Test2替代,false)] static void Test1() { Console.WriteLine(Test1); } static void Test2() { Console.WriteLine(Test2); } } }五、自定义特性 反射读取特性1. 自定义特性开发步骤创建类继承Attribute规范类名以Attribute结尾添加[AttributeUsage]限制特性使用范围AttributeTargets可标记在类 / 方法 / 字段 / 属性AllowMultiple是否允许同一个元素多次标记该特性Inherited子类是否继承该特性编写构造函数与属性存储自定义数据使用反射读取类型 / 方法上挂载的特性5.1 自定义特性类 MyAttribute.csusing System; namespace _6自定义特性 { // 限制可标记类、方法允许多次标记不被子类继承 [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; } } }5.2 反射读取特性 Demo Program.csusing System; using System.Reflection; namespace _6自定义特性 { // 类上挂载自定义特性 [My(1.0,Jack,入口类,2026-7-1)] internal class Program { static void Main(string[] args) { // 1.获取当前类Type Type t1 typeof(Program); // 2.根据方法名获取方法元数据 MethodInfo info t1.GetMethod(Test1); info?.Invoke(null,null); // 3.读取该方法所有MyAttribute特性 object[] attrs info.GetCustomAttributes(typeof(MyAttribute),false); foreach (MyAttribute attr in attrs) { Console.WriteLine(${attr.Name} : {attr.Message}); } } // 方法上多次挂载特性 [My(1.0, Jack, Test1方法, 2026-7-1)] [My(2.0, Rose, Test1方法, 2026-7-2)] public static void Test1() { Console.WriteLine(Test1); } } }读取特性固定流程Type type typeof(类名)获取类型GetMethod/GetProperty/GetField获取成员元数据GetCustomAttributes(特性类型,false)获取特性数组强转自定义特性类型读取内部存储的数据六、WinForm 自定义控件专用设计器特性开发 UserControl 自定义控件时通过特性控制VS 属性面板展示效果上位机自定义界面控件高频使用。常用设计器特性说明特性作用[Browsable(bool)]true属性在属性面板显示false 隐藏[Category(分组名)]将属性归类到指定分组[Description(说明文字)]选中属性时底部显示描述[DefaultValue(默认值)]设置默认值修改后属性名自动加粗[Obsolete()]标记控件属性废弃[DesignerCategory(Code)]告诉 VS 这是纯代码控件不打开设计器Demo UserControl1.csusing System; using System.ComponentModel; using System.Windows.Forms; namespace _7_自定义控件常用的特性 { public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } [Browsable(true)] [Category(账号分组)] [Description(登录账号文本)] [DefaultValue(佛得角)] public string Account { get textBox1.Text; set textBox1.Text value; } [Description(登录密码),Category(密码分组),DefaultValue(123),Obsolete(建议废弃该密码属性)] public string Password { get textBox2.Text; set textBox2.Text value; } } }七、反射Reflection1. 反射核心作用无需项目引用 DLL通过文件路径动态加载外部 dll在运行时获取类、方法、属性信息动态创建对象实例动态调用方法、读写属性 插件化架构、动态加载上位机驱动、动态读取配置全部依赖反射。2. 反射完整操作流程Assembly.LoadFile(dll路径)加载外部程序集CreateInstance(命名空间.类名)动态创建对象GetType()获取实例 Type 元数据GetMembers()/GetMethod()/GetProperty()获取成员信息Invoke()动态执行方法、GetValue/SetValue读写属性7.1 主程序反射代码using System; using System.IO; using System.Reflection; using System.Windows.Forms; namespace _8反射 { internal static class Program { [STAThread] static void Main() { // 1.拼接dll文件路径 string path Path.Combine(Environment.CurrentDirectory, ../../libs/ClassLibrary1.dll); // 2.加载外部dll Assembly assembly Assembly.LoadFile(path); // 3.动态创建dll内部类实例 object classObj assembly.CreateInstance(ClassLibrary1.Class1); // 4.获取类型元数据 Type type classObj.GetType(); // 5.遍历所有成员区分属性、方法 MemberInfo[] members type.GetMembers(); foreach (MemberInfo item in members) { // 读取属性值 if (item.MemberType MemberTypes.Property) { PropertyInfo prop item as PropertyInfo; Console.WriteLine(prop.GetValue(classObj) 属性值); } // 调用方法 if (item.MemberType MemberTypes.Method) { MethodInfo method item as MethodInfo; if (method.Name Test1 || method.Name Test2) { method.Invoke(classObj, null); } } } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } }7.2 外部类库 ClassLibrary1.dll 源码using System; namespace ClassLibrary1 { public class Class1 { public string Name { get; set; } 梅西; public string ID { get; set; } 001; public void Test1() { Console.WriteLine(Test1方法执行); } public string Test2() { Console.WriteLine(Test2方法执行); return test2返回值; } } }八、整体知识点串联总结委托存储方法实现回调、多播事件是封装安全的委托事件用于界面消息分发限制外部只能订阅不能随意调用特性标记代码元素分为系统内置特性、自定义特性反射运行时解析类型、读取特性、动态调用外部 DLL业务落地WinForm 控件事件 事件 委托自定义控件属性面板 设计器特性插件动态加载、配置解析 反射 自定义特性日志前置后置拦截、通用回调 委托嵌套