C#中如何扩展StringReader实现支持多步预读的Peek方法?
C# StringReader 多字符预读Peek扩展实现
实现代码
using System; using System.IO; using System.Reflection; public static class StringReaderExtensions { // 缓存私有字段反射信息,仅首次调用执行反射查询,大幅提升后续调用性能 private static readonly FieldInfo _underlyingStringField = typeof(StringReader).GetField("_s", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo _currentPositionField = typeof(StringReader).GetField("_pos", BindingFlags.Instance | BindingFlags.NonPublic); /// <summary> /// 预读指定数量的字符,不移动读取指针 /// </summary> /// <param name="reader">目标StringReader实例</param> /// <param name="count">预读字符数</param> /// <returns>预读到的字符数组,长度不超过剩余字符数</returns> /// <exception cref="ArgumentNullException">reader为null时抛出</exception> /// <exception cref="ArgumentOutOfRangeException">预读步数小于0时抛出</exception> public static char[] Peek(this StringReader reader, int count) { if (reader == null) throw new ArgumentNullException(nameof(reader)); if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "预读步数不能小于0"); if (count == 0) return Array.Empty<char>(); // 直接读取StringReader内部存储的原始字符串和当前读取位置,不修改原有状态 string originalString = (string)_underlyingStringField.GetValue(reader); int currentPos = (int)_currentPositionField.GetValue(reader); // 计算实际可取的字符数,避免越界 int availableCount = originalString.Length - currentPos; int actualTakeCount = Math.Min(count, availableCount); return actualTakeCount <= 0 ? Array.Empty<char>() : originalString.Substring(currentPos, actualTakeCount).ToCharArray(); } }
使用示例
var input = "Sample"; var reader = new StringReader(input); // 预读3个字符 var result1 = reader.Peek(3); // 结果:['S','a','m'] // 预读超过剩余长度的字符 var result2 = reader.Peek(10); // 结果:['S','a','m', 'p','l','e'] // 验证读取指针未移动 var firstChar = reader.Read(); // 输出为'S',指针仅在调用Read后才移动
注意事项
- 用到的
_s、_pos私有字段是.NET Framework、.NET Core、.NET 5+全版本通用的StringReader内置字段,兼容性稳定 - 完全符合需求要求:不移动读取指针、预读长度不足时返回所有剩余字符
- 静态缓存反射信息的设计可满足词法分析器高频调用的性能要求
内容的提问来源于stack exchange,提问作者HamedFathi
相关产品推荐
相关产品推荐

