你可能忽視的 C# 性能優(yōu)化細(xì)節(jié)
在日常開(kāi)發(fā)中,C# 提供了優(yōu)雅的語(yǔ)法和豐富的特性,讓我們能夠快速構(gòu)建功能。但在高并發(fā)或大數(shù)據(jù)量場(chǎng)景下,某些“看似無(wú)害”的寫(xiě)法,可能暗中拖累性能。
本文總結(jié)了 C# 常見(jiàn)的性能陷阱,幫你快速避坑。
1. string 拼接
字符串在 C# 中是 不可變對(duì)象,每次拼接都會(huì)分配新的內(nèi)存。
// ? 循環(huán)拼接 = O(n2) 復(fù)雜度
string result = "";
for (int i = 0; i < 1000; i++)
result += i;
// ? StringBuilder 更高效
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
sb.Append(i);
string result = sb.ToString();
?? 建議:
- ? 小規(guī)模拼接 →
+或字符串插值即可。 - ? 大規(guī)模循環(huán)拼接 →
StringBuilder。
2. LINQ vs for 循環(huán)
LINQ 簡(jiǎn)潔,但性能有代價(jià):它會(huì)創(chuàng)建迭代器對(duì)象,并產(chǎn)生額外的方法調(diào)用。
// ? LINQ 在高頻場(chǎng)景下可能偏慢
var sum = numbers.Where(x => x % 2 == 0).Sum();
// ? for 循環(huán)更高效
int sum = 0;
for (int i = 0; i < numbers.Length; i++)
if (numbers[i] % 2 == 0) sum += numbers[i];
?? 建議:
- ? 性能敏感場(chǎng)景用
for/foreach。 - ? 業(yè)務(wù)邏輯清晰優(yōu)先時(shí)用 LINQ。
3. 裝箱與拆箱
裝箱就是把值類(lèi)型(int、struct)轉(zhuǎn)成 object,拆箱再轉(zhuǎn)回來(lái)。
// ? 裝箱/拆箱開(kāi)銷(xiāo)大
object obj = 42; // 裝箱
int x = (int)obj; // 拆箱
// ? 用泛型避免裝箱
List<int> list = new List<int>();
list.Add(42);
?? 建議:
- ? 高頻操作盡量避免
object/ 非泛型集合。 - ? 使用泛型(如
List<T>、Dictionary<K,V>)。
4. 值類(lèi)型 vs 引用類(lèi)型
值類(lèi)型(struct)分配在棧上,引用類(lèi)型(class)在堆上。如果 struct 太大,頻繁復(fù)制會(huì)拖慢性能。
// ? 大 struct 會(huì)導(dǎo)致頻繁復(fù)制
struct BigStruct { public int A, B, C, D, E, F, G, H; }
// ? 用 class 或只定義小 struct
class BigClass { public int A, B, C, D, E, F, G, H; }
?? 建議:
- ? struct 小而輕(如 Point、Vector3)時(shí)使用。
- ? 大對(duì)象、復(fù)雜對(duì)象 → class。
5. 異常處理的濫用
異常的開(kāi)銷(xiāo)遠(yuǎn)大于 if 判斷。
// ? 不要用異常代替邏輯控制
try
{
int x = int.Parse("abc");
}
catch { }
// ? TryParse 更高效
if (int.TryParse("abc", out var value)) { }
?? 建議:
- ? 異常用于真正的異常場(chǎng)景。
6. async/await 的額外開(kāi)銷(xiāo)
async/await 會(huì)生成狀態(tài)機(jī)對(duì)象,帶來(lái)分配。
// ? 無(wú)意義 async
public async Task<int> GetValueAsync() => 42;
// ? 用 ValueTask
public ValueTask<int> GetValueAsync() => new(42);
?? 建議:
- ? 高頻調(diào)用的短方法 →
ValueTask。 - ? 避免“無(wú)意義 async”。
7. 不合理的集合選擇
不同集合適用場(chǎng)景不同。
| 集合類(lèi)型 | 優(yōu)勢(shì) | 不適合場(chǎng)景 |
| List | 隨機(jī)訪問(wèn)快 | 中間頻繁插入/刪除 |
| Dictionary<K,V> | 查找 O(1) | 小數(shù)據(jù)量開(kāi)銷(xiāo)大 |
| LinkedList | 插入/刪除快 | 遍歷慢 |
| HashSet | 去重/集合運(yùn)算 | 順序敏感場(chǎng)景 |
| Queue/Stack | FIFO/LIFO 高效 | 隨機(jī)訪問(wèn) |
8. 閉包(Closure)的隱形分配
閉包會(huì)導(dǎo)致捕獲的變量提升到堆上。
// ? 產(chǎn)生閉包
int counter = 0;
Func<int> f = () => counter++;
// ? 避免閉包
int Increment(int x) => x + 1;
?? 建議:
- ? 高頻循環(huán)避免創(chuàng)建閉包。
9. 大對(duì)象分配
大于 85KB 的對(duì)象會(huì)進(jìn) 大對(duì)象堆,GC 成本高。
// ? 每次分配大數(shù)組
byte[] buffer = new byte[100_000];
// ? 用 ArrayPool
var buffer = ArrayPool<byte>.Shared.Rent(100_000);
ArrayPool<byte>.Shared.Return(buffer);
?? 頻繁調(diào)用 DateTime.Now
DateTime.Now 每次都會(huì)訪問(wèn)系統(tǒng)時(shí)鐘。
// ? 高頻調(diào)用
for (int i = 0; i < 1_000_000; i++)
var t = DateTime.Now;
// ? 緩存一次
var now = DateTime.Now;
?? 建議:
- ? 高性能場(chǎng)景用
Stopwatch。
1??1?? 濫用 ToList()
ToList() 會(huì)強(qiáng)制枚舉并分配內(nèi)存。
// ? 多余的 ToList()
var evens = numbers.Where(x => x % 2 == 0).ToList();
// ? 延遲執(zhí)行更高效
foreach (var n in numbers.Where(x => x % 2 == 0))
Console.WriteLine(n);
最后
性能優(yōu)化不是“過(guò)早優(yōu)化”,而是 避免無(wú)意識(shí)的性能陷阱。
當(dāng)應(yīng)用規(guī)模變大、并發(fā)量上升時(shí),這些小細(xì)節(jié)可能決定系統(tǒng)能否扛住壓力。
?? 記住:寫(xiě)代碼先保證清晰易讀,遇到瓶頸時(shí)再結(jié)合這些技巧優(yōu)化。

浙公網(wǎng)安備 33010602011771號(hào)