前两篇写了 MyFramework 里一些常用的代码简化技巧。这一篇继续写第三组。不过这次只写真正能让调用侧代码变短的东西。也就是一眼能看到原本要写几行现在一行就能表达清楚。这类工具不是复杂系统。它们更多是项目长期开发中沉淀出来的小函数、小扩展、小短写。单独看都不大但使用频率很高。项目地址https://github.com/ZHOURUIH/MyFramework一、字符串和数字转换短写项目里数字和字符串互转非常常见。比如配置表解析UI 文本显示日志输出协议调试坐标输出百分比显示bool 状态输出原始写法通常是这样int id int.Parse(idString); float speed float.Parse(speedString); string valueText value.ToString(F2); string flag enable ? true : false;这些代码本身不难。但问题是项目里到处都要写。MyFramework 最新版本里这类转换已经大量改成扩展方法。比如字符串转整数int id idString.SToI();字符串转浮点float speed speedString.SToF();整数转字符串string idText id.IToS();long 转字符串string guidText guid.LToS();浮点转字符串并指定精度string valueText value.FToS(2);bool 转字符串string flag enable.boolToString();这类写法的价值不是 C# 原生做不到而是项目里需要统一。比如 bool 转字符串如果到处写string flag enable ? true : false;后面又有人写string flag enable ? True : False;再有人写string flag enable.ToString();项目里的输出格式就不统一。统一成string flag enable.boolToString();以后风格就固定了。真实代码里bool 转字符串是这样实现的public static string boolToString(this bool value, bool firstUpper false, bool fullUpper false) { if (fullUpper) { return value ? TRUE : FALSE; } if (firstUpper) { return value ? True : False; } return value ? true : false; }百分比显示也是一样。原本写法string percent (value * 100.0f).ToString(F1) %;现在写法string percent value.toPercent();或者指定精度string percent value.toPercent(1);真实代码public static string toPercent(this string value, int precision 1) { return (value.SToF() * 100).FToS(precision) %; } public static string toPercent(this float value, int precision 1) { return (value * 100).FToS(precision) %; }向量转字符串也统一成扩展方法。原本写法string posText pos.x.ToString(F2) , pos.y.ToString(F2) , pos.z.ToString(F2);现在写法string posText pos.V3ToS(2);真实代码public static string V3ToS(this Vector3 value, int precision 4) { return strcat(value.x.FToS(precision), ,, value.y.FToS(precision), ,, value.z.FToS(precision)); }反过来字符串转向量也可以一行完成。原本写法string[] splitList str.Split(,); Vector3 pos new(float.Parse(splitList[0]), float.Parse(splitList[1]), float.Parse(splitList[2]));现在写法Vector3 pos str.SToV3();真实代码public static Vector3 SToV3(this string str, char separate ,) { if (str.isEmpty() || str 0,0,0) { return Vector3.zero; } string[] splitList str.split(separate); if (splitList.count() 3) { return Vector3.zero; } return new(splitList[0].SToF(), splitList[1].SToF(), splitList[2].SToF()); }这类短函数的意义很明确把常见转换写成统一入口。它不会让逻辑变复杂。只是让代码更短、更统一。二、List 操作短写ListT是项目里最常用的容器之一。很多 List 操作原本都要写好几行。比如条件添加。原本写法if (condition) { list.Add(value); }现在写法list.addIf(value, condition);真实代码public static bool addIfT(this ListT list, T value, bool condition) { if (condition) { list.Add(value); } return condition; }非空才添加。原本写法if (value ! null) { list.Add(value); }现在写法list.addNotNull(value);真实代码public static bool addNotNullT(this ListT list, T value) where T : class { if (value ! null) { list.Add(value); return true; } return false; }字符串非空才添加。原本写法if (!text.isEmpty()) { list.Add(text); }现在写法list.addNotEmpty(text);真实代码public static bool addNotEmpty(this Liststring list, string value) { if (!value.isEmpty()) { list.Add(value); return true; } return false; }不重复添加。原本写法if (!list.Contains(value)) { list.Add(value); }现在写法list.addUnique(value);真实代码public static bool addUniqueT(this ListT list, T value) { if (!list.Contains(value)) { list.Add(value); return true; } return false; }有条件地不重复添加。原本写法if (condition !list.Contains(value)) { list.Add(value); }现在写法list.addUniqueIf(value, condition);真实代码public static bool addUniqueIfT(this ListT list, T value, bool condition) { if (!condition) { return false; } if (!list.Contains(value)) { list.Add(value); return true; } return false; }根据状态添加或移除。原本写法if (enable) { if (!list.Contains(value)) { list.Add(value); } } else { list.Remove(value); }现在写法list.addUniqueOrRemove(value, enable);真实代码public static void addUniqueOrRemoveT(this ListT list, T value, bool addOrRemove) { if (addOrRemove) { list.addUnique(value); } else { list.Remove(value); } }移除并返回被移除的元素。原本写法T value list[index]; list.RemoveAt(index); return value;现在写法return list.removeAt(index);真实代码public static T removeAtT(this ListT list, int index) { T value list[index]; list.RemoveAt(index); return value; }不关心顺序时可以交换到末尾再删除。现在写法return list.swapToEndAndRemove(index);真实代码public static T swapToEndAndRemoveT(this ListT list, int index) { list.swap(index, list.Count - 1); return list.removeAt(list.Count - 1); }创建新对象并添加到列表。原本写法Item item new(); list.Add(item); item.init();现在写法list.addNewItem().init();真实代码public static T addNewT(this ListT list) where T : new() { return list.add(new()); }如果添加的是对象池对象也可以写list.addClassItem().init();真实代码public static T addClassT(this ListT list) where T : ClassObject, new() { return list.add(CLASST()); }取最后一个元素。原本写法T value list null || list.Count 0 ? default : list[list.Count - 1];现在写法T value list.getLast();这类扩展函数都不复杂。但它们解决的是同一种问题不要让业务代码里到处充满重复的 if、Contains、Add、RemoveAt。比如list.addUnique(value);这一行表达得很清楚把 value 添加进列表但不要重复。这比每个地方都手写Contains Add更稳定也更统一。三、Dictionary 操作短写Dictionary的重复代码也很多。最常见的是安全取值。原本写法if (!dic.TryGetValue(key, out Value value)) { value defaultValue; }现在写法Value value dic.get(key, defaultValue);真实代码public static Value getKey, Value(this DictionaryKey, Value map, Key key, Value defaultValue) { return map ! null map.TryGetValue(key, out Value value) ? value : defaultValue; }不需要默认值时Value value dic.get(key);真实代码public static Value getKey, Value(this DictionaryKey, Value map, Key key) { if (map null) { return default; } map.TryGetValue(key, out Value value); return value; }添加或覆盖。原本写法dic[key] value;现在写法dic.addOrSet(key, value);真实代码public static void addOrSetTKey, TValue(this DictionaryTKey, TValue dic, TKey key, TValue value) { dic[key] value; }这个看起来只是换了名字但它表达更明确这个操作允许新增也允许覆盖。数值累加是更明显的简化。原本写法if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); }现在写法dic.addOrIncreaseValue(key, increase);真实代码public static void addOrIncreaseValueTKey(this DictionaryTKey, int dic, TKey key, int increase) { if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); } }根据状态添加或移除。原本写法if (isAdd) { dic.Add(key, value); } else { dic.Remove(key); }现在写法dic.addOrRemove(key, value, isAdd);真实代码public static void addOrRemoveKey, Value(this DictionaryKey, Value map, Key key, Value value, bool isAdd) { if (isAdd) { map.Add(key, value); } else { map.Remove(key); } }获取或创建普通对象。原本写法if (!map.TryGetValue(key, out Value value)) { value new(); map.Add(key, value); }现在写法map.getOrAddNew(key, out Value value);或者Value value map.getOrAddNew(key);真实代码public static bool getOrAddNewKey, Value(this DictionaryKey, Value map, Key key, out Value value) where Value : new() { if (!map.TryGetValue(key, out value)) { value new(); map.Add(key, value); return false; } return true; } public static Value getOrAddNewKey, Value(this DictionaryKey, Value map, Key key) where Value : new() { if (!map.TryGetValue(key, out Value value)) { value new(); map.Add(key, value); } return value; }获取或创建对象池对象。原本写法if (!map.TryGetValue(key, out T value)) { CLASS(out value); map.Add(key, value); }现在写法T value map.getOrAddClass(key);真实代码public static T getOrAddClassKey, T(this DictionaryKey, T map, Key key) where T : ClassObject, new() { if (!map.TryGetValue(key, out T value)) { map.Add(key, CLASS(out value)); } return value; }这类写法在事件系统、点击系统、资源系统里都很常见。比如事件监听列表mGlobalListenerEventList.getOrAddClass(info.mEventTypeID).add(info);这行代码背后做了三件事根据事件类型查找监听列表如果没有就从对象池创建一个然后把监听信息加进去如果不封装代码会变成一大段TryGetValue CLASS Add。现在一行就能表达清楚。Dictionary 这类短写非常适合框架代码。因为框架里经常会按 ID、类型、路径、状态分组。这些分组逻辑如果每次都手写字典创建代码会非常啰嗦。四、字符串截取和处理短写字符串截取也是项目里很常见的重复代码。尤其是路径、文件名、配置字段、资源名、日志文本。比如截取某个字符之前的内容。原本写法int index str.IndexOf(/); if (index 0) { str str[0..index]; }现在写法str str.rangeToFirst(/);真实代码public static string rangeToFirst(this string str, char key) { if (str null) { return str; } int endIndex str.IndexOf(key); if (endIndex 0) { return str[0..endIndex]; } return str; }截取某个字符之后的内容。现在写法str str.rangeFromFirst(/);真实代码public static string rangeFromFirst(this string str, char key) { if (str null) { return str; } int startIndex str.IndexOf(key); if (startIndex 0) { return str; } return str[(startIndex 1)..]; }截取两个字符之间的内容。原本写法int startIndex str.IndexOf((); int endIndex str.IndexOf()); if (startIndex 0 endIndex 0 endIndex startIndex) { str str[(startIndex 1)..endIndex]; }现在写法str str.rangeBetweenKeyToKey((, ));真实代码public static string rangeBetweenKeyToKey(this string str, char key0, char key1) { if (str null) { return str; } int startIndex str.IndexOf(key0); int endIndex str.IndexOf(key1); if (startIndex 0 || endIndex 0 || endIndex startIndex) { return str; } return str[(startIndex 1)..endIndex]; }移除前缀。原本写法if (str ! null str.StartsWith(prefix)) { str str[prefix.Length..]; }现在写法str str.removeStartString(prefix);真实代码public static string removeStartString(this string str, string pattern, bool caseSensitive true) { if (str null || pattern null || str.Length pattern.Length) { return str; } bool needRemove; if (caseSensitive) { needRemove str.StartsWith(pattern); } else { needRemove str.ToLower().StartsWith(pattern.ToLower()); } if (needRemove) { return str[pattern.Length..]; } return str; }移除后缀。原本写法if (str ! null str.EndsWith(suffix)) { str str[0..(str.Length - suffix.Length)]; }现在写法str str.removeEndString(suffix);真实代码public static string removeEndString(this string str, string pattern, bool caseSensitive true) { if (str null || pattern null || str.Length pattern.Length) { return str; } bool needRemove; if (caseSensitive) { needRemove str.EndsWith(pattern); } else { needRemove str.ToLower().EndsWith(pattern.ToLower()); } if (needRemove) { return str[0..(str.Length - pattern.Length)]; } return str; }确保前缀存在。原本写法if (!path.StartsWith(Assets/)) { path Assets/ path; }现在写法path path.ensurePrefix(Assets/);真实代码public static string ensurePrefix(this string str, string prefix) { if (!str.StartsWith(prefix)) { return prefix str; } return str; }确保后缀存在。原本写法if (!path.EndsWith(/)) { path /; }现在写法path path.ensureSuffix(/);真实代码public static string ensureSuffix(this string str, string prefix) { if (!str.EndsWith(prefix)) { return str prefix; } return str; }这类短写非常适合路径处理。因为路径处理里经常要做这些事去掉前缀去掉后缀截取文件夹截取文件名保证路径以/结尾保证路径以Assets/开头截取某个标记之间的内容如果每个地方都写IndexOf、Substring、StartsWith、EndsWith代码会非常散。封装成字符串扩展以后调用侧就更像自然语言。比如path path.ensureSuffix(/);这行代码一眼就能看懂确保 path 有/后缀。这就是代码简化的意义。五、数组、Span、byte[] 操作短写数组访问经常要做边界判断。原本写法T value default; if (array ! null index 0 index array.Length) { value array[index]; }现在写法T value array.get(index);真实代码public static T getT(this T[] list, int index) { if (list.isEmpty() || index 0 || index list.Length) { return default; } return list[index]; }数组设置也是一样。原本写法if (array ! null index 0 index array.Length) { array[index] value; }现在写法array.set(index, value);真实代码public static void setT(this T[] list, int index, T value) { if (list.isEmpty() || index 0 || index list.Length) { return; } list[index] value; }取第一个元素。原本写法T value array null || array.Length 0 ? default : array[0];现在写法T value array.first();真实代码public static T firstT(this T[] list) { if (list.isEmpty()) { return default; } return list[0]; }数组安全遍历。原本写法if (array ! null) { foreach (var item in array) { ... } }现在写法foreach (var item in array.safe()) { ... }真实代码public static T[] safeT(this T[] original) { return original ?? EmptyArrayT.getEmptyList(); }判断数组里是否包含某个值。原本写法bool contains false; if (array ! null) { for (int i 0; i array.Length; i) { if (equal(array[i], value)) { contains true; break; } } }现在写法bool contains array.contains(value);真实代码public static bool containsT(this T[] list, T value) { if (list.isEmpty()) { return false; } int length list.Length; for (int i 0; i length; i) { if (equal(list[i], value)) { return true; } } return false; }byte[] 转字符串也可以短写。原本写法string text Encoding.UTF8.GetString(bytes);现在写法string text bytes.bytesToString();真实代码public static string bytesToString(this byte[] bytes, Encoding encoding null) { if (bytes.isEmpty()) { return string.Empty; } // 默认为UTF8 return removeLastZero((encoding ?? Encoding.UTF8).GetString(bytes)); }Spanbyte 也可以保持同样写法string text span.bytesToString();真实代码public static string bytesToString(this Spanbyte bytes, Encoding encoding null) { if (bytes null) { return null; } if (bytes.Length 0) { return string.Empty; } // 默认为UTF8 return removeLastZero((encoding ?? Encoding.UTF8).GetString(bytes)); }这类短写解决的是两个问题。第一减少边界判断。第二统一常用转换。数组访问如果每次都手写边界判断代码会很长。但如果不判断又容易越界。所以框架提供get()、set()、first()这种短写以后调用侧更简单。byte[] 转字符串也是同理。项目里经常会有网络数据、文件数据、配置数据需要转字符串。如果到处直接写Encoding.UTF8.GetString(bytes)还要考虑空数组、尾部 0、编码默认值等问题。统一写成bytes.bytesToString();调用侧就更干净。总结这一篇基于 MyFramework 最新版本重新调整了 5 类真正能让调用侧变短的技巧字符串和数字转换短写List 操作短写Dictionary 操作短写字符串截取和处理短写数组、Span、byte[] 操作短写这一版里要特别注意很多转换函数已经是扩展方法写法。比如idString.SToI(); speedString.SToF(); id.IToS(); guid.LToS(); value.FToS(2); enable.boolToString(); pos.V3ToS(2); 0.5.toPercent(); 0.5f.toPercent();它们的共同点是原本要写几行的固定模式现在可以压成一行。比如if (!list.Contains(value)) { list.Add(value); }变成list.addUnique(value);比如if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); }变成dic.addOrIncreaseValue(key, increase);比如int index str.IndexOf(/); if (index 0) { str str[0..index]; }变成str str.rangeToFirst(/);比如if (array ! null index 0 index array.Length) { value array[index]; }变成value array.get(index);这些不是为了隐藏业务逻辑。它们隐藏的是每天都会重复出现的样板代码。一句话总结代码简化不是少写业务。而是不要让业务代码被重复的固定写法淹没。
Unity MyFramework:框架里的代码简化技巧(三)
发布时间:2026/7/6 13:04:39
前两篇写了 MyFramework 里一些常用的代码简化技巧。这一篇继续写第三组。不过这次只写真正能让调用侧代码变短的东西。也就是一眼能看到原本要写几行现在一行就能表达清楚。这类工具不是复杂系统。它们更多是项目长期开发中沉淀出来的小函数、小扩展、小短写。单独看都不大但使用频率很高。项目地址https://github.com/ZHOURUIH/MyFramework一、字符串和数字转换短写项目里数字和字符串互转非常常见。比如配置表解析UI 文本显示日志输出协议调试坐标输出百分比显示bool 状态输出原始写法通常是这样int id int.Parse(idString); float speed float.Parse(speedString); string valueText value.ToString(F2); string flag enable ? true : false;这些代码本身不难。但问题是项目里到处都要写。MyFramework 最新版本里这类转换已经大量改成扩展方法。比如字符串转整数int id idString.SToI();字符串转浮点float speed speedString.SToF();整数转字符串string idText id.IToS();long 转字符串string guidText guid.LToS();浮点转字符串并指定精度string valueText value.FToS(2);bool 转字符串string flag enable.boolToString();这类写法的价值不是 C# 原生做不到而是项目里需要统一。比如 bool 转字符串如果到处写string flag enable ? true : false;后面又有人写string flag enable ? True : False;再有人写string flag enable.ToString();项目里的输出格式就不统一。统一成string flag enable.boolToString();以后风格就固定了。真实代码里bool 转字符串是这样实现的public static string boolToString(this bool value, bool firstUpper false, bool fullUpper false) { if (fullUpper) { return value ? TRUE : FALSE; } if (firstUpper) { return value ? True : False; } return value ? true : false; }百分比显示也是一样。原本写法string percent (value * 100.0f).ToString(F1) %;现在写法string percent value.toPercent();或者指定精度string percent value.toPercent(1);真实代码public static string toPercent(this string value, int precision 1) { return (value.SToF() * 100).FToS(precision) %; } public static string toPercent(this float value, int precision 1) { return (value * 100).FToS(precision) %; }向量转字符串也统一成扩展方法。原本写法string posText pos.x.ToString(F2) , pos.y.ToString(F2) , pos.z.ToString(F2);现在写法string posText pos.V3ToS(2);真实代码public static string V3ToS(this Vector3 value, int precision 4) { return strcat(value.x.FToS(precision), ,, value.y.FToS(precision), ,, value.z.FToS(precision)); }反过来字符串转向量也可以一行完成。原本写法string[] splitList str.Split(,); Vector3 pos new(float.Parse(splitList[0]), float.Parse(splitList[1]), float.Parse(splitList[2]));现在写法Vector3 pos str.SToV3();真实代码public static Vector3 SToV3(this string str, char separate ,) { if (str.isEmpty() || str 0,0,0) { return Vector3.zero; } string[] splitList str.split(separate); if (splitList.count() 3) { return Vector3.zero; } return new(splitList[0].SToF(), splitList[1].SToF(), splitList[2].SToF()); }这类短函数的意义很明确把常见转换写成统一入口。它不会让逻辑变复杂。只是让代码更短、更统一。二、List 操作短写ListT是项目里最常用的容器之一。很多 List 操作原本都要写好几行。比如条件添加。原本写法if (condition) { list.Add(value); }现在写法list.addIf(value, condition);真实代码public static bool addIfT(this ListT list, T value, bool condition) { if (condition) { list.Add(value); } return condition; }非空才添加。原本写法if (value ! null) { list.Add(value); }现在写法list.addNotNull(value);真实代码public static bool addNotNullT(this ListT list, T value) where T : class { if (value ! null) { list.Add(value); return true; } return false; }字符串非空才添加。原本写法if (!text.isEmpty()) { list.Add(text); }现在写法list.addNotEmpty(text);真实代码public static bool addNotEmpty(this Liststring list, string value) { if (!value.isEmpty()) { list.Add(value); return true; } return false; }不重复添加。原本写法if (!list.Contains(value)) { list.Add(value); }现在写法list.addUnique(value);真实代码public static bool addUniqueT(this ListT list, T value) { if (!list.Contains(value)) { list.Add(value); return true; } return false; }有条件地不重复添加。原本写法if (condition !list.Contains(value)) { list.Add(value); }现在写法list.addUniqueIf(value, condition);真实代码public static bool addUniqueIfT(this ListT list, T value, bool condition) { if (!condition) { return false; } if (!list.Contains(value)) { list.Add(value); return true; } return false; }根据状态添加或移除。原本写法if (enable) { if (!list.Contains(value)) { list.Add(value); } } else { list.Remove(value); }现在写法list.addUniqueOrRemove(value, enable);真实代码public static void addUniqueOrRemoveT(this ListT list, T value, bool addOrRemove) { if (addOrRemove) { list.addUnique(value); } else { list.Remove(value); } }移除并返回被移除的元素。原本写法T value list[index]; list.RemoveAt(index); return value;现在写法return list.removeAt(index);真实代码public static T removeAtT(this ListT list, int index) { T value list[index]; list.RemoveAt(index); return value; }不关心顺序时可以交换到末尾再删除。现在写法return list.swapToEndAndRemove(index);真实代码public static T swapToEndAndRemoveT(this ListT list, int index) { list.swap(index, list.Count - 1); return list.removeAt(list.Count - 1); }创建新对象并添加到列表。原本写法Item item new(); list.Add(item); item.init();现在写法list.addNewItem().init();真实代码public static T addNewT(this ListT list) where T : new() { return list.add(new()); }如果添加的是对象池对象也可以写list.addClassItem().init();真实代码public static T addClassT(this ListT list) where T : ClassObject, new() { return list.add(CLASST()); }取最后一个元素。原本写法T value list null || list.Count 0 ? default : list[list.Count - 1];现在写法T value list.getLast();这类扩展函数都不复杂。但它们解决的是同一种问题不要让业务代码里到处充满重复的 if、Contains、Add、RemoveAt。比如list.addUnique(value);这一行表达得很清楚把 value 添加进列表但不要重复。这比每个地方都手写Contains Add更稳定也更统一。三、Dictionary 操作短写Dictionary的重复代码也很多。最常见的是安全取值。原本写法if (!dic.TryGetValue(key, out Value value)) { value defaultValue; }现在写法Value value dic.get(key, defaultValue);真实代码public static Value getKey, Value(this DictionaryKey, Value map, Key key, Value defaultValue) { return map ! null map.TryGetValue(key, out Value value) ? value : defaultValue; }不需要默认值时Value value dic.get(key);真实代码public static Value getKey, Value(this DictionaryKey, Value map, Key key) { if (map null) { return default; } map.TryGetValue(key, out Value value); return value; }添加或覆盖。原本写法dic[key] value;现在写法dic.addOrSet(key, value);真实代码public static void addOrSetTKey, TValue(this DictionaryTKey, TValue dic, TKey key, TValue value) { dic[key] value; }这个看起来只是换了名字但它表达更明确这个操作允许新增也允许覆盖。数值累加是更明显的简化。原本写法if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); }现在写法dic.addOrIncreaseValue(key, increase);真实代码public static void addOrIncreaseValueTKey(this DictionaryTKey, int dic, TKey key, int increase) { if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); } }根据状态添加或移除。原本写法if (isAdd) { dic.Add(key, value); } else { dic.Remove(key); }现在写法dic.addOrRemove(key, value, isAdd);真实代码public static void addOrRemoveKey, Value(this DictionaryKey, Value map, Key key, Value value, bool isAdd) { if (isAdd) { map.Add(key, value); } else { map.Remove(key); } }获取或创建普通对象。原本写法if (!map.TryGetValue(key, out Value value)) { value new(); map.Add(key, value); }现在写法map.getOrAddNew(key, out Value value);或者Value value map.getOrAddNew(key);真实代码public static bool getOrAddNewKey, Value(this DictionaryKey, Value map, Key key, out Value value) where Value : new() { if (!map.TryGetValue(key, out value)) { value new(); map.Add(key, value); return false; } return true; } public static Value getOrAddNewKey, Value(this DictionaryKey, Value map, Key key) where Value : new() { if (!map.TryGetValue(key, out Value value)) { value new(); map.Add(key, value); } return value; }获取或创建对象池对象。原本写法if (!map.TryGetValue(key, out T value)) { CLASS(out value); map.Add(key, value); }现在写法T value map.getOrAddClass(key);真实代码public static T getOrAddClassKey, T(this DictionaryKey, T map, Key key) where T : ClassObject, new() { if (!map.TryGetValue(key, out T value)) { map.Add(key, CLASS(out value)); } return value; }这类写法在事件系统、点击系统、资源系统里都很常见。比如事件监听列表mGlobalListenerEventList.getOrAddClass(info.mEventTypeID).add(info);这行代码背后做了三件事根据事件类型查找监听列表如果没有就从对象池创建一个然后把监听信息加进去如果不封装代码会变成一大段TryGetValue CLASS Add。现在一行就能表达清楚。Dictionary 这类短写非常适合框架代码。因为框架里经常会按 ID、类型、路径、状态分组。这些分组逻辑如果每次都手写字典创建代码会非常啰嗦。四、字符串截取和处理短写字符串截取也是项目里很常见的重复代码。尤其是路径、文件名、配置字段、资源名、日志文本。比如截取某个字符之前的内容。原本写法int index str.IndexOf(/); if (index 0) { str str[0..index]; }现在写法str str.rangeToFirst(/);真实代码public static string rangeToFirst(this string str, char key) { if (str null) { return str; } int endIndex str.IndexOf(key); if (endIndex 0) { return str[0..endIndex]; } return str; }截取某个字符之后的内容。现在写法str str.rangeFromFirst(/);真实代码public static string rangeFromFirst(this string str, char key) { if (str null) { return str; } int startIndex str.IndexOf(key); if (startIndex 0) { return str; } return str[(startIndex 1)..]; }截取两个字符之间的内容。原本写法int startIndex str.IndexOf((); int endIndex str.IndexOf()); if (startIndex 0 endIndex 0 endIndex startIndex) { str str[(startIndex 1)..endIndex]; }现在写法str str.rangeBetweenKeyToKey((, ));真实代码public static string rangeBetweenKeyToKey(this string str, char key0, char key1) { if (str null) { return str; } int startIndex str.IndexOf(key0); int endIndex str.IndexOf(key1); if (startIndex 0 || endIndex 0 || endIndex startIndex) { return str; } return str[(startIndex 1)..endIndex]; }移除前缀。原本写法if (str ! null str.StartsWith(prefix)) { str str[prefix.Length..]; }现在写法str str.removeStartString(prefix);真实代码public static string removeStartString(this string str, string pattern, bool caseSensitive true) { if (str null || pattern null || str.Length pattern.Length) { return str; } bool needRemove; if (caseSensitive) { needRemove str.StartsWith(pattern); } else { needRemove str.ToLower().StartsWith(pattern.ToLower()); } if (needRemove) { return str[pattern.Length..]; } return str; }移除后缀。原本写法if (str ! null str.EndsWith(suffix)) { str str[0..(str.Length - suffix.Length)]; }现在写法str str.removeEndString(suffix);真实代码public static string removeEndString(this string str, string pattern, bool caseSensitive true) { if (str null || pattern null || str.Length pattern.Length) { return str; } bool needRemove; if (caseSensitive) { needRemove str.EndsWith(pattern); } else { needRemove str.ToLower().EndsWith(pattern.ToLower()); } if (needRemove) { return str[0..(str.Length - pattern.Length)]; } return str; }确保前缀存在。原本写法if (!path.StartsWith(Assets/)) { path Assets/ path; }现在写法path path.ensurePrefix(Assets/);真实代码public static string ensurePrefix(this string str, string prefix) { if (!str.StartsWith(prefix)) { return prefix str; } return str; }确保后缀存在。原本写法if (!path.EndsWith(/)) { path /; }现在写法path path.ensureSuffix(/);真实代码public static string ensureSuffix(this string str, string prefix) { if (!str.EndsWith(prefix)) { return str prefix; } return str; }这类短写非常适合路径处理。因为路径处理里经常要做这些事去掉前缀去掉后缀截取文件夹截取文件名保证路径以/结尾保证路径以Assets/开头截取某个标记之间的内容如果每个地方都写IndexOf、Substring、StartsWith、EndsWith代码会非常散。封装成字符串扩展以后调用侧就更像自然语言。比如path path.ensureSuffix(/);这行代码一眼就能看懂确保 path 有/后缀。这就是代码简化的意义。五、数组、Span、byte[] 操作短写数组访问经常要做边界判断。原本写法T value default; if (array ! null index 0 index array.Length) { value array[index]; }现在写法T value array.get(index);真实代码public static T getT(this T[] list, int index) { if (list.isEmpty() || index 0 || index list.Length) { return default; } return list[index]; }数组设置也是一样。原本写法if (array ! null index 0 index array.Length) { array[index] value; }现在写法array.set(index, value);真实代码public static void setT(this T[] list, int index, T value) { if (list.isEmpty() || index 0 || index list.Length) { return; } list[index] value; }取第一个元素。原本写法T value array null || array.Length 0 ? default : array[0];现在写法T value array.first();真实代码public static T firstT(this T[] list) { if (list.isEmpty()) { return default; } return list[0]; }数组安全遍历。原本写法if (array ! null) { foreach (var item in array) { ... } }现在写法foreach (var item in array.safe()) { ... }真实代码public static T[] safeT(this T[] original) { return original ?? EmptyArrayT.getEmptyList(); }判断数组里是否包含某个值。原本写法bool contains false; if (array ! null) { for (int i 0; i array.Length; i) { if (equal(array[i], value)) { contains true; break; } } }现在写法bool contains array.contains(value);真实代码public static bool containsT(this T[] list, T value) { if (list.isEmpty()) { return false; } int length list.Length; for (int i 0; i length; i) { if (equal(list[i], value)) { return true; } } return false; }byte[] 转字符串也可以短写。原本写法string text Encoding.UTF8.GetString(bytes);现在写法string text bytes.bytesToString();真实代码public static string bytesToString(this byte[] bytes, Encoding encoding null) { if (bytes.isEmpty()) { return string.Empty; } // 默认为UTF8 return removeLastZero((encoding ?? Encoding.UTF8).GetString(bytes)); }Spanbyte 也可以保持同样写法string text span.bytesToString();真实代码public static string bytesToString(this Spanbyte bytes, Encoding encoding null) { if (bytes null) { return null; } if (bytes.Length 0) { return string.Empty; } // 默认为UTF8 return removeLastZero((encoding ?? Encoding.UTF8).GetString(bytes)); }这类短写解决的是两个问题。第一减少边界判断。第二统一常用转换。数组访问如果每次都手写边界判断代码会很长。但如果不判断又容易越界。所以框架提供get()、set()、first()这种短写以后调用侧更简单。byte[] 转字符串也是同理。项目里经常会有网络数据、文件数据、配置数据需要转字符串。如果到处直接写Encoding.UTF8.GetString(bytes)还要考虑空数组、尾部 0、编码默认值等问题。统一写成bytes.bytesToString();调用侧就更干净。总结这一篇基于 MyFramework 最新版本重新调整了 5 类真正能让调用侧变短的技巧字符串和数字转换短写List 操作短写Dictionary 操作短写字符串截取和处理短写数组、Span、byte[] 操作短写这一版里要特别注意很多转换函数已经是扩展方法写法。比如idString.SToI(); speedString.SToF(); id.IToS(); guid.LToS(); value.FToS(2); enable.boolToString(); pos.V3ToS(2); 0.5.toPercent(); 0.5f.toPercent();它们的共同点是原本要写几行的固定模式现在可以压成一行。比如if (!list.Contains(value)) { list.Add(value); }变成list.addUnique(value);比如if (dic.TryGetValue(key, out int curValue)) { dic[key] curValue increase; } else { dic.Add(key, increase); }变成dic.addOrIncreaseValue(key, increase);比如int index str.IndexOf(/); if (index 0) { str str[0..index]; }变成str str.rangeToFirst(/);比如if (array ! null index 0 index array.Length) { value array[index]; }变成value array.get(index);这些不是为了隐藏业务逻辑。它们隐藏的是每天都会重复出现的样板代码。一句话总结代码简化不是少写业务。而是不要让业务代码被重复的固定写法淹没。