临时字符串0GC解决方案--OneString

OneString是一种创新的0GC解决方案,用于将数字和布尔值转换为字符串而无需产生垃圾回收。该方案支持多种数据类型,包括int、long、float、double和bool,并允许设置浮点数精度。通过提供临时字符串的复用,OneString在打印或临时显示数值时显著减少内存消耗。
OneString 是一个 0 GC ToString 解决方案。传统的数字或者bool变量转换成string的时候会产生GC。由于string是不可变的,每次修改string的值,内部都会生成一个新的string。如果我们需要临时打印某个值,使用系统提供的 ToString 函数就会不可避免地产生一个新的string,我们其实并不需要保存这个string的值,仅仅是为了打印一下,这是我们不想看到的结果。因此如果有一个临时字符串在我们使用之后,自动回收重复利用,并且不会产生GC就好了。OneString 就是这样一个解决方案。不过需要注意的是像 UGUI 的Text 组件里面的值,这种需要用来显示使用的,不要使用此方案,因为Text的值会被修改掉。

特点

  • 0 GC:To String 不会产生 GC。
  • 支持 int、long、float、double、bool 等。
  • 支持设置浮点数的精度,默认是保留小数点后两位。
  • 便于使用:直接使用 ToOneString() 函数即可,它会返回一个临时string。
  • 支持扩展和修改。
  • 包含完整的代码和demo场景。

安装

Player Settings: 勾选 Allow ‘unsafe’ Code 。 直接使用 ToOneString() 即可,它会返回一个临时字符串string。

文档

PDF

Release Note

1.0.1

Init release

联系

更多信息,请看网站: [https://assetstore.unity.com/packages/slug/168465 ](https://assetstore.unity.com/packages/slug/168465 )
#region 串口通讯 public class SerialPortComm : IDisposable { #region 字段与事件 private readonly SerialPort serialPort; private bool disposed = false; public event Action<Exception> ErrorOccurred; /// <summary> /// 数据接收事件 /// 当串口收到数据时触发,参数为接收到的 byte[] 数组 /// 使用示例:comm.PortData += data => { /* 处理数据 */ }; /// 注意:此事件在工作线程中触发,更新 UI 需使用 Invoke /// </summary> public event Action<byte[]> PortData; #endregion #region 构造函数 /// <summary> /// 无参构造:默认配置串口参数 /// </summary> public SerialPortComm() { serialPort = new SerialPort(); InitializeDefaultSettings(); } /// <summary> /// 带参构造:指定串口号和波特率 /// </summary> /// <param name="portName">串口名称,如 COM3</param> /// <param name="baudRate">波特率,如 9600</param> public SerialPortComm(string portName, int baudRate) : this() { if (!string.IsNullOrEmpty(portName)) serialPort.PortName = portName; if (baudRate > 0) serialPort.BaudRate = baudRate; } /// <summary> /// 初始化默认串口设置 /// 包括数据位、停止位、奇偶校验、握手协议、超时时间等 /// </summary> private void InitializeDefaultSettings() { serialPort.DataBits = 8; //--------------------数据位:8位 serialPort.StopBits = StopBits.One; //---------停止位:1位 serialPort.Parity = Parity.None; //------------奇偶校验:无 serialPort.Handshake = Handshake.None; //------握手协议:无 serialPort.ReadTimeout = 500; //---------------读取超时:500ms serialPort.WriteTimeout = 500; //--------------写入超时:500ms // 绑定数据接收事件:当串口有数据到达时,自动调用 OnDataReceived 方法 serialPort.DataReceived += OnDataReceived; } #endregion #region 串口初始化 /// <summary> /// 初始化串口参数(端口名和波特率) /// 必须在串口未打开的状态下才能修改 /// </summary> /// <param name="portName">要设置的串口号,如 "COM4"</param> /// <param name="baudRate">要设置的波特率,如 115200</param> public void IniSerialPort(string portName, int baudRate) { // 防止对象已被销毁后调用 if (disposed) throw new ObjectDisposedException(nameof(SerialPortComm)); // 如果串口已经打开,则不允许修改配置 if (serialPort.IsOpen) return; // 设置串口号(仅当输入有效时) if (!string.IsNullOrEmpty(portName)) serialPort.PortName = portName; // 设置波特率(仅当输入合法时) if (baudRate > 0) serialPort.BaudRate = baudRate; } /// <summary> /// 获取系统中可用的串口列表 /// </summary> public static string[] GetAvailablePorts() { return SerialPort.GetPortNames(); } #endregion #region 打开/关闭 /// <summary> /// 打开串口 /// 调用 SerialPort.Open() 方法启动通信 /// 出错时弹出消息框提示用户 /// </summary> public void Open() { // 检查对象是否已被释放 if (disposed) throw new ObjectDisposedException(nameof(SerialPortComm)); try { // 只有在未打开的情况下才执行打开操作 if (!serialPort.IsOpen) serialPort.Open(); } catch (Exception ex) { // 1. 记录错误日志(便于调试) System.Diagnostics.Debug.WriteLine($"[SerialPortComm] 打开串口失败: {ex.Message}"); // 2. 触发错误事件,让上层订阅者自行处理(例如弹窗、写日志等) OnError(ex); } } /// <summary> /// 关闭串口 /// </summary> public void Close() { if (disposed) return; try { if (serialPort.IsOpen) { serialPort.DiscardInBuffer(); // 清空输入缓冲 serialPort.DiscardOutBuffer(); // 清空输出缓冲 serialPort.Close(); // 关闭串口 } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("关闭串口异常:" + ex.Message); } } #endregion #region 状态查询 /// <summary> /// 获取串口是否已打开 /// </summary> /// <returns>true 表示已打开</returns> public bool IsOpen() => serialPort.IsOpen; #endregion #region 数据写入 /// <summary> /// 发送字符串数据 /// 使用当前编码(默认为 ASCII)将字符串转为字节发送 /// </summary> /// <param name="msg">要发送的字符串</param> public void Write(string msg) { // 参数检查:空字符串不发送 if (string.IsNullOrEmpty(msg)) return; try { if (serialPort.IsOpen) serialPort.Write(msg); } catch (Exception ex) { OnError(ex); } } /// <summary> /// 发送字节数组 /// 适用于发送二进制命令(如 Modbus、相机控制指令) /// </summary> /// <param name="data">要发送的 byte[] 数组</param> public void Write(byte[] data) { if (data == null || data.Length == 0) return; try { if (serialPort.IsOpen) serialPort.Write(data, 0, data.Length); } catch (Exception ex) { OnError(ex); } } /// <summary> /// 发送字符数组 /// 类似于 Write(string),但支持 char[] 输入 /// </summary> /// <param name="data">要发送的 char[] 数组</param> public void Write(char[] data) { if (data == null || data.Length == 0) return; try { if (serialPort.IsOpen) serialPort.Write(data, 0, data.Length); } catch (Exception ex) { OnError(ex); } } #endregion #region 数据读取 /// <summary> /// 数据接收事件处理方法 /// 当串口检测到有数据到达时,系统自动调用此方法 /// </summary> /// <param name="sender">事件源对象(即 SerialPort)</param> /// <param name="e">事件参数</param> private void OnDataReceived(object sender, SerialDataReceivedEventArgs e) { try { // 获取当前有多少字节可读 int count = serialPort.BytesToRead; // 如果没有数据,直接返回 if (count == 0) return; // 创建缓冲区存储数据 byte[] buffer = new byte[count]; int read = serialPort.Read(buffer, 0, count); // 确保实际读取数量大于0 if (read > 0) { // 使用临时数组确保长度准确 byte[] data = new byte[read]; Array.Copy(buffer, data, read); // 触发事件(注意:此事件在工作线程中执行) PortData?.Invoke(data); } } catch (Exception ex) { OnError(ex); } } #endregion #region 错误处理辅助 /// <summary> /// 统一错误处理入口 /// 可用于记录日志或通知上层 /// </summary> /// <param name="ex">发生的异常</param> private void OnError(Exception ex) { System.Diagnostics.Debug.WriteLine("串口错误:" + ex.Message); } #endregion #region 串口关闭 /// <summary> /// 实现 IDisposable 接口 /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposed) return; if (disposing) { serialPort?.Dispose(); // 释放 SerialPort 资源 } disposed = true; } #endregion } #endregion
10-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值