目录
[3.1 使用泛型集合替代非泛型集合](#3.1 使用泛型集合替代非泛型集合)
[3.2 使用StringBuilder和插值优化字符串操作](#3.2 使用StringBuilder和插值优化字符串操作)
[3.3 使用结构体或者值元组](#3.3 使用结构体或者值元组)
1.什么是装箱/拆箱
装箱是将值类型转换为引用类型的过程,拆箱则相反。看似简单的操作,背后却隐藏着巨大的性能开销:
cs// 装箱 - 值类型转换为object int value = 42; object boxed = value; // 在堆上分配内存,复制数据 // 拆箱 - object转换回值类型 int unboxed = (int)boxed; // 类型检查 + 数据复制
2.性能杀手:隐式装箱
csstatic void Main(string[] args) { // 看似无害的代码,实际上发生了大量装箱 var list = new ArrayList(); for (int i = 0; i < 1000000; i++) { list.Add(i); // 每次都装箱! } // 字符串拼接中的隐式装箱 string result = ""; for (int i = 0; i < 10000; i++) { result += "Number: " + i; // i被装箱转换为object } }
3.性能优化方案
3.1 使用泛型集合替代非泛型集合
泛型集合明确集合类型,防止出现隐式装箱操纵
cs// 高性能:使用泛型List<T> publicclass OptimizedExample { public void ProcessNumbers() { List<int> numbers = new List<int>(); // 无装箱:直接存储值类型 for (int i = 0; i < 100000; i++) { numbers.Add(i); } // 无拆箱:直接访问值类型 int sum = 0; foreach (int num in numbers) { sum += num; // 直接操作,无类型转换 } } }
3.2 使用StringBuilder和插值优化字符串操作
问题代码:
cs// 字符串拼接中的装箱陷阱 public string FormatNumbers(int[] numbers) { string result = ""; foreach (int num in numbers) { result += "Value: " + num + ", "; // num被装箱 } return result; }
优化代码:
cs// 使用StringBuilder和字符串插值避免装箱 public string FormatNumbersOptimized(int[] numbers) { var sb = new StringBuilder(); foreach (int num in numbers) { sb.Append($"Value: {num}, "); // 直接格式化,避免装箱 } return sb.ToString(); } // 更高效的Span<T>方式(.NET Core 2.1+) public string FormatNumbersWithSpan(ReadOnlySpan<int> numbers) { var sb = new StringBuilder(); foreach (int num in numbers) { sb.Append("Value: "); sb.Append(num); // 直接追加值类型 sb.Append(", "); } return sb.ToString(); }
3.3 使用结构体或者值元组
问题代码:
cs// 装箱发生在这里 object[] data = { 42, "Hello", 3.14, true }; // 拆箱发生在这里 int intVal = (int)data[0]; string strVal = (string)data[1]; double doubleVal = (double)data[2]; bool boolVal = (bool)data[3];
优化代码:
csvar data = new DataItem(42, "Hello", 3.14, true); // 无装箱 //值元组 var data = (IntValue: 42, StringValue: "Hello", DoubleValue: 3.14, BoolValue: true);
3.4 使用Memory和Span优化内存操作
问题代码:
cs// 传统数组操作可能导致装箱 public int SumArray(object[] values) { int sum = 0; for (int i = 0; i < values.Length; i++) { sum += (int)values[i]; // 拆箱操作 } return sum; }
优化代码:
cs// 使用Span<T>和Memory<T>零拷贝操作 public int SumArrayOptimized(ReadOnlySpan<int> values) { int sum = 0; for (int i = 0; i < values.Length; i++) { sum += values[i]; // 直接访问,无装箱拆箱 } return sum; } // 更安全的Memory<T>版本 public int SumMemory(ReadOnlyMemory<int> memory) { var span = memory.Span; int sum = 0; foreach (int value in span) { sum += value; } return sum; } // 实际使用示例 public void UseOptimizedArrays() { int[] numbers = { 1, 2, 3, 4, 5 }; // 零拷贝操作 int sum1 = SumArrayOptimized(numbers); int sum2 = SumMemory(numbers.AsMemory()); }
记住这三个黄金法则:
-
能用泛型就用泛型
类型安全且高性能
-
值类型优于引用类型
减少堆分配和GC压力
-
Span/Memory是性能利器
零拷贝操作的最佳选择