在 C# 项目开发过程中,性能优化是提升程序质量的重要环节,合理的优化手段能够减少内存占用、降低 CPU 消耗、提升响应速度。本文将从多个实用维度介绍 C# 性能优化的具体技巧,所有示例均基于实际开发场景设计。

一、内存管理与垃圾回收优化
内存管理是 C# 性能优化的核心方向之一,不合理的对象创建和引用会导致频繁的垃圾回收,影响程序性能。
1. 避免不必要的对象创建
频繁创建短生命周期的对象会增加垃圾回收的压力,对于可复用的对象可以考虑使用对象池或者缓存机制。
using System;
using System.Collections.Generic;
public class ObjectPool<T> where T : new()
{
private readonly Stack<T> _pool = new Stack<T>();
private readonly int _maxSize;
public ObjectPool(int maxSize = 100)
{
_maxSize = maxSize;
}
// 从池中获取对象
public T Get()
{
if (_pool.Count > 0)
{
return _pool.Pop();
}
return new T();
}
// 将对象归还到池
public void Return(T obj)
{
if (_pool.Count < _maxSize)
{
// 可以在这里重置对象状态
_pool.Push(obj);
}
}
}
// 使用示例
public class TestObject
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main()
{
var pool = new ObjectPool<TestObject>();
var obj1 = pool.Get();
obj1.Id = 1;
obj1.Name = "测试对象";
// 使用完成后归还
pool.Return(obj1);
var obj2 = pool.Get(); // 此时获取到的是之前归还的对象,避免重新创建
}
}
2. 合理使用值类型与引用类型
值类型存储在栈上,不需要垃圾回收,而引用类型存储在堆上,会产生回收开销。对于小型、不可变的数据结构,优先使用值类型。
using System;
// 值类型示例,结构体适合存储小型数据
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
class Program
{
static void Main()
{
// 值类型创建在栈上,无堆内存分配
Point p1 = new Point(10, 20);
Point p2 = p1; // 复制值,不是引用
p2.X = 30;
Console.WriteLine(p1.X); // 输出10,p1的值不受影响
}
}
二、循环与集合操作优化
循环和集合操作是程序中高频执行的代码段,优化这部分逻辑能带来明显的性能提升。
1. 循环中的优化技巧
避免在循环内部做不必要的操作,比如重复调用方法、重复创建对象等。
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<int> data = new List<int>();
for (int i = 0; i < 10000; i++)
{
data.Add(i);
}
// 不好的写法:每次循环都调用Count属性
// for (int i = 0; i < data.Count; i++) { ... }
// 优化写法:提前缓存集合长度
int count = data.Count;
for (int i = 0; i < count; i++)
{
// 循环逻辑
int value = data[i] * 2;
}
// 遍历集合时,如果是List优先使用for循环,比foreach性能更好
// 数组遍历同样优先使用for循环
}
}
2. 选择合适的集合类型
不同的集合类型适用场景不同,选择匹配场景的集合能减少不必要的性能损耗。
| 集合类型 | 适用场景 | 性能特点 |
|---|---|---|
| List<T> | 需要频繁按索引访问、添加元素的场景 | 索引访问快,尾部添加效率高 |
| LinkedList<T> | 需要频繁在中间插入、删除元素的场景 | 插入删除快,索引访问慢 |
| Dictionary<TKey, TValue> | 需要通过键快速查找值的场景 | 查找效率高,基于哈希表实现 |
| HashSet<T> | 需要存储不重复元素、判断元素是否存在的场景 | 去重和存在性判断效率高 |
三、异步编程优化
合理使用异步编程可以避免线程阻塞,提升程序的吞吐量和响应速度,尤其适合 IO 密集型操作。
1. 避免不必要的异步开销
对于纯 CPU 密集型操作,不需要使用异步,异步本身会带来一定的上下文切换开销。
using System;
using System.Threading.Tasks;
class Program
{
// 不好的写法:CPU密集操作使用异步,徒增开销
// public async Task<int> CalculateBadAsync()
// {
// await Task.Run(() => { return 1 + 2; });
// return result;
// }
// 优化写法:CPU密集操作直接同步执行
public int Calculate()
{
return 1 + 2;
}
// IO密集操作适合使用异步,比如文件读取、网络请求
public async Task<string> ReadFileAsync(string path)
{
using var reader = System.IO.File.OpenText(path);
return await reader.ReadToEndAsync();
}
}
2. 正确使用异步方法
异步方法要避免使用Task.Wait()、Task.Result等阻塞调用,防止死锁和性能问题。
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
// 不好的写法:阻塞异步任务
// var result = GetDataAsync().Result;
// 优化写法:使用await异步等待
var result = await GetDataAsync();
Console.WriteLine(result);
}
static async Task<string> GetDataAsync()
{
await Task.Delay(100); // 模拟异步操作
return "数据内容";
}
}
四、其他实用优化技巧
1. 字符串操作优化
频繁的字符串拼接会产生大量临时字符串对象,优先使用StringBuilder处理多次拼接场景。
using System;
using System.Text;
class Program
{
static void Main()
{
// 不好的写法:多次字符串拼接
// string str = "";
// for (int i = 0; i < 1000; i++)
// {
// str += i.ToString();
// }
// 优化写法:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append(i);
}
string result = sb.ToString();
}
}
2. 避免装箱拆箱操作
装箱拆箱会产生堆内存分配和类型转换开销,对于值类型和 object 类型的交互场景,尽量使用泛型避免装箱。
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
static void Main()
{
// 不好的写法:ArrayList存储值类型,会产生装箱
// ArrayList list = new ArrayList();
// list.Add(1); // 值类型1装箱为object
// 优化写法:使用泛型集合List<int>,避免装箱
List<int> genericList = new List<int>();
genericList.Add(1); // 无装箱操作
}
}