C#结构体,枚举,泛型,事件,委托--10
目录
一.结构体
二.特殊的结构体(ref struct):
三.枚举
四.泛型
泛型的使用:
1.泛型类:定义一个泛型类,使用类型参数T
2.泛型方法:在方法定义中使用类型参数
3.泛型接口
五.委托及泛型委托
委托
泛型委托
六.事件
事件:
泛型事件:使用泛型委托(如EventHandler)来声明事件,可以传递更具体的事件数据。
七.事件,委托,泛型结合使用
总结
一.结构体
定义:
struct关键字用于声明一个值类型.结构体适合表示轻量级对象,如坐标,复杂数等
特点:
- 值类型:数据存储在栈(Stack)上,变量直接包含数据值
- 不可继承:结构体不支持继承(无法被继承,也不能继承自其他类型,除了实现接口)
- 默认不可为空:值类型变量默认情况下不能为null(除非使用Nullable<T>)
- 内存效率:在栈上分配和释放,效率较高,适合小型数据结构
用法:
- 不适合过大的数据结构,否则会影响性能
- 结构体应设计为不可变(Immutability),即成员应尽量设为只读
代码示例:
public struct Point
{public double X { get; }public double Y { get; }public Point(double x, double y){X = x;Y = y;}
}
二.特殊的结构体(ref struct):
定义:
- ref struct是一种特殊的结构体,限制其只能在栈上分配,不能在堆上分配
特点:
- 仅限栈分配:ref struct实例不能被分配到托管堆上,保证了高性能的内存访问
- 无法装箱:不能转换为object类型,不能使用如泛型,接口等需要装箱的特性
- 用途限定:常用于需要高性能和低延迟的场景,例如Span<T>,ReadonlySpan<T>等类型
限制:
- 不能捕获到异步方法,迭代器或Lambda表达式中:因为这些场景中可能导致变量逃逸出栈
- 不能赋值给类型为
object的变量 - 不能实现接口
代码示例:
public ref struct SpanWrapper
{private Span<byte> _buffer;public SpanWrapper(Span<byte> buffer){_buffer = buffer;}// 成员方法和属性
}
三.枚举
定义:enum关键字用于声明一个枚举类型,由命名常量的集合组成
特点:
- 值类型:枚举的底层类型是整型(默认是int),每个枚举成员都有一个关联的整数值
- 提高可读性:使用有意义的名称代替数字,提高代码的可读性和可维护性
- 可指定底层类型:可以显式指定底层类型,例如byte,short等
- 位标志(Flags):使用
[Flags]属性可以让枚举表示位域,支持按位操作
代码示例:
public enum DaysOfWeek : byte
{Sunday = 0,Monday = 1,Tuesday = 2,Wednesday = 3,Thursday = 4,Friday = 5,Saturday = 6
}// 使用枚举
DaysOfWeek today = DaysOfWeek.Monday;
位标志代码示例:
[Flags]
public enum FileAccess
{Read = 1,Write = 2,Execute = 4
}// 组合权限
FileAccess readWrite = FileAccess.Read | FileAccess.Write; // 1|2=3
//同时拥有读和写的权限
四.泛型
定义:
- 泛型是C# 2.0引入的一个特性,允许在定义类,接口,方法和委托时,使用类型参数,从而实现代码的类型安全和重用性
优势:
- 类型安全:在编译时检查类型,防止由于类型不匹配导致的运行时错误。
- 性能提升:避免了装箱(boxing)和拆箱(unboxing)的开销。
- 代码重用:编写一次代码,可适用于多种数据类型。
泛型的使用:
1.泛型类:定义一个泛型类,使用类型参数T
定义泛型类:
public class GenericClass<T>
{private T _value;public GenericClass(T value){_value = value;}public T GetValue(){return _value;}
}
使用泛型类:
GenericClass<int> intInstance = new GenericClass<int>(10);
int intValue = intInstance.GetValue(); // intValue = 10GenericClass<string> stringInstance = new GenericClass<string>("Hello");
string stringValue = stringInstance.GetValue(); // stringValue = "Hello"
2.泛型方法:在方法定义中使用类型参数
定义泛型方法:
public class Utility
{public void Swap<T>(ref T a, ref T b){T temp = a;a = b;b = temp;}
}
使用泛型方法:
Utility utility = new Utility();
int x = 5, y = 10;
utility.Swap<int>(ref x, ref y); // 交换整数string s1 = "First", s2 = "Second";
utility.Swap<string>(ref s1, ref s2); // 交换字符串
3.泛型接口
定义一个泛型接口:
public interface IRepository<T>
{void Add(T item);T Get(int id);
}
实现泛型接口:
public class Repository<T> : IRepository<T>
{private List<T> _items = new List<T>();public void Add(T item){_items.Add(item);}public T Get(int id){return _items[id];}
}
五.委托及泛型委托
委托
定义:
- 委托是C#中的一种数据类型,它定义了一个方法的类型,使得方法可以作为参数传递。委托类似于函数指针,但它是类型安全的。
基本语法:public delegate 返回类型 委托名(参数列表);
定义委托:
public delegate int MathOperation(int a, int b);
使用委托:
public class Calculator
{public int Add(int a, int b) => a + b;public int Subtract(int a, int b) => a - b;
} public class Program
{// 定义一个委托类型public delegate int Operation(int x, int y);public static void Main(){Calculator calc = new Calculator();// 创建委托实例并指向Add方法Operation op = new Operation(calc.Add);Console.WriteLine(op(3, 4)); // 输出: 7// 改变委托指向Subtract方法op = new Operation(calc.Subtract);Console.WriteLine(op(10, 4)); // 输出: 6}
}
泛型委托
使用泛型参数的委托类型,增强了委托的灵活性和可重用性
常用的泛型委托:
Func<T1,...,TResult>:有返回值的委托,可有0到16个输入参数
Func<int, int, int> multiply = (a, b) => a * b;
int product = multiply(3, 4); // product = 12
Action<T1,...>:无返回值的委托,可有0到16个输入参数。
Action<string> display = message => Console.WriteLine(message);
display("Hello, World!"); // 输出:Hello, World!
Predicate<T>:返回bool类型的委托,常用于条件判断。
Predicate<int> isPositive = number => number > 0;
bool check = isPositive(5); // check = true
自定义泛型委托:
public delegate TOutput Converter<TInput, TOutput>(TInput input);class Program
{static void Main(){Converter<double, int> doubleToInt = num => (int)num;int result = doubleToInt(3.14); // result = 3}
}
六.事件
定义:
- 事件是委托的特殊形式,用于在对象之间传递消息或通知.当对象的状态发生改变时,可以通过事件通知订阅者.事件是基于“发布-订阅”(Publish-Subscribe)模式的实现
基本语法:public event 委托类型 事件名;
事件:
定义委托和事件:
// 定义委托
public delegate void NotifyEventHandler(string message);// 定义发布者类
public class Publisher
{// 声明事件public event NotifyEventHandler Notify;public void DoSomething(){// 执行某些操作// 触发事件OnNotify("事件被触发.");}protected virtual void OnNotify(string message){// 检查是否有订阅者Notify?.Invoke(message);}
}
订阅事件:
// 定义订阅者类
public class Subscriber
{public void OnNotified(string message){Console.WriteLine($"Received message: {message}");}
}
使用事件:
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();// 订阅事件
publisher.Notify += subscriber.OnNotified;// 触发事件
publisher.DoSomething(); // 输出:Received message: 事件被触发.
泛型事件:使用泛型委托(如EventHandler<TEventArgs>)来声明事件,可以传递更具体的事件数据。
使用EventHandler<TEventArgs>:
// 定义事件参数类
public class ProgressEventArgs : EventArgs
{public int Percentage { get; set; }
}// 定义发布者类
public class Process
{// 声明泛型事件public event EventHandler<ProgressEventArgs> ProgressChanged;public void StartProcess(){for (int i = 0; i <= 100; i += 10){// 模拟处理过程// 触发事件OnProgressChanged(i);}}protected virtual void OnProgressChanged(int percentage){ProgressChanged?.Invoke(this, new ProgressEventArgs { Percentage = percentage });}
}
订阅泛型事件:
public class Listener
{public void Subscribe(Process process){process.ProgressChanged += OnProgressChanged;}private void OnProgressChanged(object sender, ProgressEventArgs e){Console.WriteLine($"Process is {e.Percentage}% complete.");}
}
使用泛型事件:
Process process = new Process();
Listener listener = new Listener();listener.Subscribe(process);
process.StartProcess();// 输出:
// Process is 0% complete.
// Process is 10% complete.
// ...
// Process is 100% complete.
七.事件,委托,泛型结合使用
代码示例:
// 定义泛型委托
public delegate void ValueChangedEventHandler<T>(object sender, ValueChangedEventArgs<T> e);// 定义泛型事件参数类
public class ValueChangedEventArgs<T> : EventArgs
{public T OldValue { get; set; }public T NewValue { get; set; }
}// 定义发布者类
public class ObservableProperty<T>
{private T _value;// 声明泛型事件public event ValueChangedEventHandler<T> ValueChanged;public T Value{get => _value;set{if (!_value.Equals(value)){T oldValue = _value;_value = value;OnValueChanged(oldValue, _value);}}}protected virtual void OnValueChanged(T oldValue, T newValue){ValueChanged?.Invoke(this, new ValueChangedEventArgs<T> { OldValue = oldValue, NewValue = newValue });}
}// 定义订阅者类
public class PropertyObserver<T>
{public void Subscribe(ObservableProperty<T> property){property.ValueChanged += OnValueChanged;}private void OnValueChanged(object sender, ValueChangedEventArgs<T> e){Console.WriteLine($"Value changed from {e.OldValue} to {e.NewValue}");}
}
使用示例:
ObservableProperty<string> nameProperty = new ObservableProperty<string> { Value = "Alice" };
PropertyObserver<string> observer = new PropertyObserver<string>();observer.Subscribe(nameProperty);
nameProperty.Value = "Bob"; // 输出:Value changed from Alice to Bob
总结
-
泛型(Generics):允许在类,接口,方法和委托中使用类型参数,提高了代码的类型安全性和重用性
-
委托(Delegate):是用于引用方法的类型,支持将方法作为参数传递.泛型委托增强了委托的灵活性
-
事件(Event):基于委托的发布-订阅机制,用于在对象间发送通知和消息.泛型事件可以传递特定类型的数据,使事件处理更加强大和类型安全
相关文章:
C#结构体,枚举,泛型,事件,委托--10
目录 一.结构体 二.特殊的结构体(ref struct): 三.枚举 四.泛型 泛型的使用: 1.泛型类:定义一个泛型类,使用类型参数T 2.泛型方法:在方法定义中使用类型参数 3.泛型接口 五.委托及泛型委托 委托 泛型委托 六.事件 事件: 泛型事件:使用泛型委托(如Event…...
MapReduce完整工作流程
1、mapreduce工作流程(终极版) 0. 任务提交 1. 拆-split逻辑切片--任务切分。 FileInputFormat--split切片计算工具 FileSplit--单个计算任务的数据范围。 2. 获得split信息和个数。 MapTask阶段 1. 读取split范围内的数据。k(偏移量)-v(行数据) 关键API:TextI…...
网络编程(1)
网络编程概述 Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里&#…...
mysql中创建计算字段
目录 1、计算字段 2、拼接字段 3、去除空格和使用别名 (1)去除空格 (2)使用别名:AS 4、执行算术计算 5、小结 博主用的是mysql8 DBMS,附上示例资料: 百度网盘链接: https://pan.baidu.co…...
【算法】判断一个链表是否为回文结构
问: 给定一个单链表的头节点head,请判断该链表是否为回文结构 例: 1 -> 2 -> 1返回true;1 -> 2 -> 2 -> 1返回true;15 -> 6 -> 15返回true 答: 笔试:初始化一个栈用来…...
计算机网络之---ICMP协议与Ping命令
ICMP 协议 ICMP (Internet Control Message Protocol) 是一种网络层协议,主要用于在 IP 网络中传递控制消息。ICMP 主要用于网络设备之间的故障报告和诊断,帮助设备检测网络连接问题。它是 IP 协议的核心部分之一,用于发送错误消息和操作信息…...
【硬件介绍】Type-C接口详解
一、Type-C接口概述 Type-C接口特点:以其独特的扁头设计和无需区分正反两面的便捷性而广受欢迎。这种设计大大提高了用户的使用体验,避免了传统USB接口需要多次尝试才能正确插入的问题。Type-C接口内部结构:内部上下两排引脚的设计虽然可能不…...
【Pandas】pandas Series rtruediv
Pandas2.2 Series Binary operator functions 方法描述Series.add()用于对两个 Series 进行逐元素加法运算Series.sub()用于对两个 Series 进行逐元素减法运算Series.mul()用于对两个 Series 进行逐元素乘法运算Series.div()用于对两个 Series 进行逐元素除法运算Series.true…...
项目开发版本控制Git流程规范
个人&测试&预发布&生产分支命名 1)个人分支: 从sit或者master进行切出,姓名切出分支命名,或者日期切出分支命名 示例:liuys_sit、20250110_sit2)测试分支: sit3)用户验…...
STM32 : 波特率发生器
波特率发生器 1. 发送器和接收器的波特率 波特率寄存器 (BRR): 在串行通信中,发送器和接收器的波特率是由波特率寄存器(BRR)中的一个值 DIV 来确定的。 2. 计算公式 计算公式: 详细解释 1. 波特率寄存器 (BRR) BRR: 波特率寄存器是一…...
STM32 USB组合设备 MSC CDC
STM32 USB组合设备 MSC CDC实现 教程 教程请看大佬niu_88 手把手教你使用USB的CDCMSC复合设备(基于stm32f407) 大佬的教程很好,很详细,我调出来了,代码请见我绑定的资源 注意事项 值得注意的是: 1、 cu…...
继续以“实用”指导Pythonic编码(re通配表达式)(2024年终总结2)
弃现成工具手剥任务🧐,我哈哈滴就像笨笨的傻大个儿😋。 (笔记模板由python脚本于2025年01月12日 23:29:33创建,本篇笔记适合熟悉正则表达式的coder翻阅) 【学习的细节是欢悦的历程】 Python官网:https://www.python.or…...
Flutter使用BorderRadiusTween实现由矩形变成圆形的动画
BorderRadiusTween 是插值动画中,用于组件边框半径的类,专门作用于组件边框和半径动化过度。 这个类继承自Tween,用法相似。 下面是示例写法 class BorderRadiusTweenPage extends StatefulWidget {overrideState<StatefulWidget> c…...
VSCode 中的 launch.json 配置使用
VSCode 中的 launch.json 配置使用 在 VSCode 中,launch.json 文件用于配置调试设置,特别是用来定义如何启动和调试你的应用。它允许你配置不同的调试模式、运行参数和调试选项。 基本结构 launch.json 文件位于 .vscode 文件夹内,可以通过…...
深度学习张量的秩、轴和形状
深度学习张量的秩、轴和形状 秩、轴和形状是在深度学习中我们最关心的张量属性。 秩轴形状 秩、轴和形状是在深度学习中开始使用张量时我们最关心的三个属性。这些概念相互建立,从秩开始,然后是轴,最后构建到形状,所以请注意这…...
Redis有哪些常用应用场景?
大家好,我是锋哥。今天分享关于【Redis有哪些常用应用场景?】面试题。希望对大家有帮助; Redis有哪些常用应用场景? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Redis 是一个高性能的开源键值对(Key-Va…...
vue3+ts+element-plus 输入框el-input设置背景颜色
普通情况: 组件内容: <el-input v-model"applyBasicInfo.outerApplyId"/> 样式设置: ::v-deep .el-input__wrapper {background-color: pink; }// 也可以这样设置 ::v-deep(.el-input__wrapper) {background-color: pink…...
Ubuntu 磁盘修复
Ubuntu 磁盘修复 在 ubuntu 文件系统变成只读模式,该处理呢? 文件系统内部的错误,如索引错误、元数据损坏等,也可能导致系统进入只读状态。磁盘坏道或硬件故障也可能引发文件系统只读的问题。/etc/fstab配置错误,可能…...
使用RSyslog将Nginx Access Log写入Kafka
个人博客地址:使用RSyslog将Nginx Access Log写入Kafka | 一张假钞的真实世界 环境说明 CentOS Linux release 7.3.1611kafka_2.12-0.10.2.2nginx/1.12.2rsyslog-8.24.0-34.el7.x86_64.rpm 创建测试Topic $ ./kafka-topics.sh --zookeeper 192.168.72.25:2181/k…...
通过Apache、Nginx限制直接访问public下的静态文件
一、Apache 在public目录下的.htaccess文件中添加如下规则,来拒绝除了指定文件类型之外的所有请求 <FilesMatch "\.(?!(jpg|jpeg|png|gif|css|js|ico)$)[^.]$">Order Allow,DenyDeny from all </FilesMatch> 上述配置表示仅允许访问.jpg …...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
前言:本文将向开发者介绍一款创新性协作工具——Neko虚拟浏览器。在数字化协作场景中,跨地域的团队常需面对实时共享屏幕、协同编辑文档等需求。通过本指南,你将掌握在Ubuntu系统中使用容器化技术部署该工具的具体方案,并结合内网…...
