C#基础11-常用类
1、String
(1)基础特性
不可变性
C# 字符串(string
)是引用类型,但内容不可修改。
每次操作(如拼接、替换)都会创建新对象,旧对象由 GC 回收。频繁操作可能影响性能。
类似字符数组
可通过索引访问单个字符(如 str[0]
),但不能直接修改(如 str[0] = 'a'
会报错)。
需转换为 char[]
修改后再转回字符串:
csharp
复制代码
char[] chars = str.ToCharArray();
chars[1] = '为';
str = new string(chars); // 重新生成字符串
(2)常用操作
大小写转换:忽略用户输入大小写(如 Console.ReadLine().ToLower()
)
csharp
复制代码
string lower = str.ToLower(); // 转为小写
string upper = str.ToUpper(); // 转为大写
csharp
复制代码
string trimmed = str.Trim(); // 移除首尾空格
string customTrim = str.Trim('a', 'b'); // 移除首尾指定字符(如 'a'/'b')
csharp
复制代码
// 分割
string[] words = str.Split(new char[] { ' ', ',', '?' }, StringSplitOptions.RemoveEmptyEntries);
// 合并
string joined = string.Join("-", new string[] { "A", "B", "C" }); // 输出 "A-B-C"
csharp
复制代码
string sub1 = str.Substring(3); // 从索引3截取到末尾
string sub2 = str.Substring(3, 2); // 从索引3截取2个字符
csharp
复制代码
bool contains = str.Contains("abc"); // 是否包含子串
int index = str.IndexOf("abc"); // 首次出现位置(不存在返回-1)
bool starts = str.StartsWith("He"); // 是否以指定字符串开头
csharp
复制代码
byte[] utf8Bytes = Encoding.UTF8.GetBytes(str); // 字符串 → UTF-8字节
string fromGBK = Encoding.GetEncoding("GBK").GetString(bytes); // 字节 → 字符串
(3)性能优化
避免频繁拼接:循环内拼接字符串时,优先使用 StringBuilder
,效率比+=
提升数十倍
csharp
复制代码
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.Append("text");
}
string result = sb.ToString(); // 最终生成字符串
高效字符串比较 :使用 StringComparison.Ordinal
或 OrdinalIgnoreCase
进行字节级比较,避免文化差异影响,性能提升显著:
csharp
复制代码
bool equal = string.Equals(str1, str2, StringComparison.OrdinalIgnoreCase);
(4)格式化输出
String.Format
与占位符:{index[,alignment][:formatString]}
csharp
复制代码
string.Format("Name: {0,-10} Salary: {1,6:C}", "Bill", 123456);
// 输出:Name: Bill Salary: ¥123,456.00
复制代码
- `index`:参数索引(从0开始)
- `alignment`:对齐方式(正数右对齐,负数左对齐)
- `formatString`:格式代码
csharp
复制代码
string name = "Polly";
decimal salary = 7890.5m;
Console.WriteLine($"{name,-10} {salary,6:C}");
// 输出:Polly ¥7,890.50
标识符
说明
示例(输入123456.42)
输出
C
/c
货币格式
{0:C2}
¥123,456.42
D
/d
十进制整数
{0:D8}
00123456
F
/f
定点小数
{0:F3}
123456.420
N
/n
千位分隔数字
{0:N0}
123,456
P
/p
百分比
{0:P1}
(输入0.42)
42.0%
X
/x
十六进制
{0:X}
(输入255)
FF
E
/e
科学计数法
{0:E2}
1.23E+005
符号
作用
示例(输入1234.56)
输出
0
零占位符(补位)
{0:000000.000}
001234.560
#
数字占位符(去空)
{0:####.##}
1234.56
.
小数点
{0:0.000}
1234.560
,
千位分隔符/缩放倍数
{0:0,.} {0:0,,}
1 (缩放千/百万倍)
%
百分比转换
{0:0%}
(输入0.42)
42%
;
分段格式化(正/负/零)
{0:正数:#;负数:(#);零}
正数:1234
csharp
复制代码
Console.WriteLine($"{123456.42:#,##0.00;(#,##0.00);zero}"); // 123,456.42
Console.WriteLine($"{-123456.42:#,##0.00;(#,##0.00);zero}"); // (123,456.42)
区域性设置:使用 CultureInfo
适配本地化格式
csharp
复制代码
double value = 1234.56;
string enUS = string.Format(CultureInfo.GetCultureInfo("en-US"), "{0:C}", value); // $1,234.56
string zhCN = string.Format(CultureInfo.GetCultureInfo("zh-CN"), "{0:C}", value); // ¥1,234.56
2、StringBuilder
(1)基础用法
csharp
复制代码
// 初始化字符串 + 设置初始容量
StringBuilder sb = new StringBuilder("Hello", 20); //
Console.WriteLine($"Capacity: {sb.Capacity}"); // 输出 20
csharp
复制代码
sb.Append(" World!"); // "Hello World!"
复制代码
- `AppendFormat()`:格式化追加
csharp
复制代码
int price = 25;
sb.AppendFormat(" Price: {0:C}", price); // "Hello World! Price: $25.00"
csharp
复制代码
sb.Insert(6, "C# "); // "Hello C# World!"
复制代码
- `Remove()`:删除子串
csharp
复制代码
sb.Remove(5, 4); // 删除索引5开始的4个字符 → "Hello World!"
csharp
复制代码
sb.Replace("World", "Universe"); // "Hello Universe!"
复制代码
- `Clear()`:清空内容
csharp
复制代码
sb.Clear(); // 长度归零
(2)性能优化
预分配容量
避免频繁扩容:初始化时预估最大长度(如日志拼接),减少内存复制开销。
避免链式操作
错误示例:sb.Append("A").Append("B").Append("C");
改进:单次Append()
合并内容:
csharp
复制代码
sb.Append("A").Append("B"); // 少量操作可接受
Unity游戏开发场景
在循环中拼接字符串时,StringBuilder
比String
减少90%的GC(垃圾回收)压力:
csharp
复制代码
StringBuilder result = new StringBuilder();
for (int i = 0; i < 1000; i++) {
result.Append(i); // 无临时字符串产生
}
(3)与String的差异
特性
String
StringBuilder
可变性
不可变(修改生成新对象)
可变(原地修改字符数组)
内存开销
高(频繁修改时)
低(预分配缓冲池)
线程安全
是
❌ 非线程安全(需手动同步)
适用场景
单次操作、常量字符串
循环拼接、动态构建大文本
(4)高级方法
csharp
复制代码
char[] buffer = new char[10];
sb.CopyTo(0, buffer, 0, 5); // 复制前5字符到数组
csharp
复制代码
sb.EnsureCapacity(50); // 确保容量≥50
csharp
复制代码
if (sb.Length == 0) { /* 空对象 */ } // 比ToString()更高效
(5)实战示例
csharp
复制代码
using System.Text;
StringBuilder log = new StringBuilder("Start: ", 100);
// 批量追加
log.AppendLine("Operation 1 completed.")
.AppendFormat("Time: {0:HH:mm}", DateTime.Now);
// 替换关键词
log.Replace("completed", "SUCCESS");
// 输出结果
Console.WriteLine(log.ToString());
输出:
Start: Operation 1 SUCCESS.
Time: 14:30
3、DateTime
(1)基础操作
csharp
复制代码
DateTime now = DateTime.Now; // 当前本地时间
DateTime utcNow = DateTime.UtcNow; // 当前 UTC 时间
DateTime today = DateTime.Today; // 当天日期(时间部分为 00:00:00)
属性示例
now.Year
(年份)
now.Month
(月份)
now.Day
(日)
now.Hour
(小时)
now.Minute
(分钟)
now.Second
(秒)
构造指定日期
csharp
复制代码
DateTime customDate = new DateTime(2025, 9, 3); // 2025年9月3日
DateTime withTime = new DateTime(2025, 9, 3, 14, 30, 0); // 含具体时间
(2)格式化输出
csharp
复制代码
string shortDate = now.ToString("d"); // "2025/9/3"(短日期)
string longDate = now.ToString("D"); // "2025年9月3日"
string iso8601 = now.ToString("s"); // "2025-09-03T17:15:55"(ISO 标准)
csharp
复制代码
string customFormat = now.ToString("yyyy-MM-dd HH:mm:ss"); // "2025-09-03 17:15:55"
string monthName = now.ToString("MMM", new CultureInfo("en-US")); // "SEP"(英文月份缩写)
csharp
复制代码
string dateOnly = now.ToShortDateString(); // 短日期字符串(如 "2025/9/3")
string timeOnly = now.ToShortTimeString(); // 短时间字符串(如 "17:15")
️(3)比较与判断
csharp
复制代码
int result = DateTime.Compare(date1, date2);
// result < 0:date1 早于 date2;result > 0:date1 晚于 date2
csharp
复制代码
bool isLater = date1 > date2; // 判断先后
bool isSameDay = date1.Date == date2.Date; // 是否同一天
csharp
复制代码
DayOfWeek day = now.DayOfWeek; // 返回枚举(如 DayOfWeek.Wednesday)
bool isLeapYear = DateTime.IsLeapYear(now.Year); // 是否为闰年
(4)运算与时间差
csharp
复制代码
DateTime tomorrow = now.AddDays(1); // 加1天
DateTime lastMonth = now.AddMonths(-1); // 减1个月
DateTime nextHour = now.AddHours(1); // 加1小时
csharp
复制代码
TimeSpan diff = date2 - date1;
Console.WriteLine($"相差:{diff.Days}天,{diff.Hours}小时");
精确单位:diff.TotalDays
(总天数)、diff.TotalMinutes
(总分钟数)
(5)实用场景
csharp
复制代码
DateTime lastDay = new DateTime(now.Year, now.Month, 1).AddMonths(1).AddDays(-1);
// 或使用内置方法:
int lastDayNum = DateTime.DaysInMonth(now.Year, now.Month); // 当月总天数
csharp
复制代码
int workingDays = 0;
for (DateTime d = startDate; d <= endDate; d = d.AddDays(1))
{
if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
workingDays++;
}
(6)注意事项
时区处理:涉及跨时区应用时,优先使用 DateTime.UtcNow
协调时间,避免本地时区混淆。
性能优化:频繁操作日期时(如循环计算),避免重复调用 DateTime.Now
(每次调用需系统交互),可缓存初始值。
4、TimeSpan
(1)创建实例
构造函数 :参数顺序(days, hours, minutes, seconds, milliseconds)
。
csharp
复制代码
TimeSpan ts1 = new TimeSpan(10, 30, 0); // 10小时30分钟
TimeSpan ts2 = new TimeSpan(2, 14, 18, 35); // 2天14小时18分35秒
TimeSpan ts3 = new TimeSpan(0, 0, 0, 0, 500); // 500毫秒
csharp
复制代码
TimeSpan.FromDays(3.5); // 3天12小时
TimeSpan.FromMinutes(90); // 1小时30分钟
TimeSpan.FromMilliseconds(1500); // 1.5秒
(2)算时间差
csharp
复制代码
DateTime start = new DateTime(2025, 1, 1, 8, 0, 0);
DateTime end = new DateTime(2025, 1, 1, 17, 30, 45);
TimeSpan duration = end - start; // 或 end.Subtract(start);
Console.WriteLine(duration); // 输出: 09:30:45
结果可通过属性获取部分值(如 duration.Hours
返回 9)或总量(如 duration.TotalHours
返回 9.5125)。
(3)关键属性
属性
说明
示例值 (duration)
Days
间隔的天数部分(不包含小时转换)
0
Hours
小时部分(0-23)
9
TotalHours
总小时数(含小数)
9.5125
TotalMinutes
总分钟数
570.75
Milliseconds
毫秒部分(0-999)
0
Ticks
100纳秒为单位的间隔(1秒=10^7)
342450000000
(4)格式转换
字符串转 TimeSpan:
支持格式:"6:15:30"
、"1.12:24:02"
(1天12小时)。
csharp
复制代码
TimeSpan ts = TimeSpan.Parse("06:15:30"); // 格式: [d.]hh:mm:ss[.fffffff]
bool success = TimeSpan.TryParse("6.15:30", out ts); // 安全解析(推荐)
csharp
复制代码
ts.ToString(@"dd\.hh\:mm\:ss"); // 输出 "01.12:24:02"
$"{ts:%d}天 {ts:%h}小时"; // 输出 "1天 12小时"
(5)常见问题
精度问题:DateTime
最小单位是毫秒,TimeSpan
最小单位是 Tick(100纳秒),高精度计算需用 Ticks
。
负数间隔:若 start > end
,TimeSpan
属性值为负,可用 Duration()
取绝对值。
5、Stopwatch
(1)核心功能
csharp
复制代码
Stopwatch stopwatch = new Stopwatch(); // 创建实例
stopwatch.Start(); // 启动计时
// 执行待测代码(如数据库查询、算法等)
stopwatch.Stop(); // 停止计时
TimeSpan elapsed = stopwatch.Elapsed; // 获取时间间隔
Console.WriteLine($"耗时:{elapsed.TotalMilliseconds}ms");
csharp
复制代码
// 一行代码完成计时
TimeSpan elapsed = Stopwatch.StartNew(() => {
// 待测代码
}).Elapsed;
(2)注意事项
csharp
复制代码
for (int i = 0; i < 10; i++) {
Stopwatch sw = new Stopwatch(); // 可能因种子相同导致时间值重复
sw.Start();
// ...
}
复制代码
- 正确做法(复用静态实例):
csharp
复制代码
static Stopwatch sw = new Stopwatch(); // 类级静态对象
for (int i = 0; i < 10; i++) {
sw.Restart(); // 重置并启动
// ...
sw.Stop();
}
场景
方案
.NET 6+
直接使用线程安全的 Stopwatch.StartNew()
旧版本.NET
为每个线程分配独立实例:new ThreadLocal<Random>(() => new Stopwatch())
精度与局限性
最高精度:依赖硬件支持,通常为 100纳秒级(通过 Stopwatch.IsHighResolution
检测)。
不适用场景:加密、安全相关操作(需改用 RNGCryptoServiceProvider
)。
(3)高级技巧
csharp
复制代码
Stopwatch sw = Stopwatch.StartNew();
MethodA();
sw.Stop();
TimeSpan timeA = sw.Elapsed;
sw.Restart(); // 重置计时器
MethodB();
sw.Stop();
TimeSpan timeB = sw.Elapsed;
csharp
复制代码
var timings = new List<long>();
for (int i = 0; i < 100; i++) {
sw.Restart();
// 执行代码
sw.Stop();
timings.Add(sw.ElapsedTicks); // 记录每次耗时(高精度)
}
double avgTicks = timings.Average();
csharp
复制代码
using (SqlConnection conn = new SqlConnection(connStr)) {
conn.Open();
Stopwatch sw = Stopwatch.StartNew();
// 执行查询
var data = conn.Query("SELECT * FROM LargeTable");
sw.Stop();
Log($"查询耗时:{sw.ElapsedMilliseconds}ms");
}
(4)场景优化
场景
推荐实践
短时操作测量
多次运行取平均值(避免单次误差)
Web API响应监控
在中间件中集成Stopwatch,记录接口耗时
算法效率对比
结合GC.Collect()
和GC.WaitForPendingFinalizers()
排除GC干扰
高频调用代码分析
使用ElapsedTicks
替代毫秒计数(更高精度)
6、Math
(1)数学运算
取绝对值
Math.Abs(-5.3)
→ 5.3
(支持整数、浮点数)
幂与根号
幂运算:Math.Pow(2, 3)
→ 8
(计算2的3次方)
平方根:Math.Sqrt(9)
→ 3
指数与对数
自然指数:Math.Exp(2)
≈ 7.389
(e²)
常用对数:Math.Log10(100)
→ 2
(log₁₀100)
(2)取整与舍入
方法
说明
示例
结果
Math.Ceiling
向上取整
Math.Ceiling(2.1)
3
Math.Floor
向下取整
Math.Floor(2.9)
2
Math.Round
(默认)
银行家算法(四舍六入五取偶)
Math.Round(2.5)
2
Math.Round
(指定模式)
强制四舍五入
Math.Round(2.5, MidpointRounding.AwayFromZero)
3
csharp
复制代码
Math.Round(Convert.ToDecimal(526.925), 2, MidpointRounding.AwayFromZero); // 返回526.93
(3)三角函数
Math.Sin(Math.PI/6)
→ 0.5
(参数为弧度)
Math.Atan2(y, x)
:计算点 (x,y)
的反正切角(自动处理象限)
csharp
复制代码
double angle = Math.Atan2(7, 7) * 180 / Math.PI; // 输出45°
(4)高级工具库
功能:矩阵运算、线性代数、微积分等科学计算。
安装:
bash
复制代码
Install-Package MathNet.Numerics
csharp
复制代码
using MathNet.Numerics.LinearAlgebra;
var matrix = DenseMatrix.OfArray(new double[,] {{1, 2}, {3, 4}});
var subMatrix = matrix.SubMatrix(0, 2, 0, 1); // 提取前两行、第一列
(5)关键常量
Math.PI
:圆周率π ≈ 3.14159
Math.E
:自然对数底e ≈ 2.71828
(6)最佳实践
精度问题:财务计算优先用 decimal
,避免 double
浮点误差。
矩阵运算:简单矩阵用原生数组,复杂计算(如求逆、特征值)用 Math.NET (效率提升10倍+)。
7、Random
(1)核心功能
csharp
复制代码
Random rand = new Random(); // 推荐在类级别声明为静态对象
复制代码
- 指定种子:相同种子生成相同随机序列(适用于测试)
csharp
复制代码
Random fixedRand = new Random(123); // 种子值固定
方法
作用
示例
Next()
生成0~2,147,483,647的整数
rand.Next()
→ 198273
Next(int max)
生成0~max-1的整数
rand.Next(100)
→ 0~99
Next(int min, int max)
生成min~max-1的整数
rand.Next(10, 20)
→ 10~19
NextDouble()
生成0.0~1.0的双精度浮点数
rand.NextDouble()
→ 0.784
NextBytes(byte[] buffer)
填充随机字节数组
byte[] buf = new byte[8]; rand.NextBytes(buf);
(2)注意事项
csharp
复制代码
for (int i = 0; i < 5; i++)
{
Random r = new Random(); // 可能生成相同随机数(间隔<15ms时)
Console.WriteLine(r.Next());
}
复制代码
- 正确做法:复用同一实例!
csharp
复制代码
static Random rand = new Random(); // 静态对象保证单例
for (int i = 0; i < 5; i++)
{
Console.WriteLine(rand.Next(100)); // 输出不同随机数
}
多线程安全方案
.NET 6+:使用线程安全的 Random.Shared
csharp
复制代码
int num = Random.Shared.Next(1, 100); // 无需手动管理实例
复制代码
- 旧版本:为每个线程创建独立实例
csharp
复制代码
private static readonly ThreadLocal<Random> threadRand =
new ThreadLocal<Random>(() => new Random(Guid.NewGuid().GetHashCode()));
随机性局限性
Random
生成的是伪随机数,不适合加密等高安全场景(需改用 RNGCryptoServiceProvider
)
浮点数精度:NextDouble()
范围是 [0.0, 1.0)
,不含1.0
(3)进阶技巧
csharp
复制代码
// 生成[-100, 100)的整数
int num = rand.Next(-100, 100);
// 生成[0.5, 5.5)的浮点数
double value = rand.NextDouble() * 5.0 + 0.5;
csharp
复制代码
// 随机字符串(a-z, 0-9)
string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
string randomStr = new string(Enumerable.Repeat(chars, 8)
.Select(s => s[rand.Next(s.Length)]).ToArray()); // 如 "a3f8bz2r"
(4)最佳实践
场景
推荐方案
原因
单线程应用
静态 Random
实例
避免重复种子问题
多线程应用
Random.Shared
(.NET 6+)或 ThreadLocal<Random>
线程安全且高效
加密/安全场景
System.Security.Cryptography.RandomNumberGenerator
真随机性要求
测试用例
固定种子的 Random
结果可复现
8、Guid
(1)核心功能
csharp
复制代码
Guid guid = Guid.NewGuid(); // 默认生成V4格式(128位随机值)
Console.WriteLine(guid); // 输出:9af7f46a-ea52-4aa3-b8c3-9fd484c2af12
复制代码
- 时间序生成(V7,.NET 9+)
csharp
复制代码
Guid guidV7 = Guid.CreateVersion7(); // 基于时间戳+随机数,适合数据库主键
Console.WriteLine(guidV7); // 输出:01917bbe-d973-7beb-a813-106fcb4eff98
格式符
输出示例
适用场景
D
(默认)
9af7f46a-ea52-4aa3-b8c3-...
日志、显示
N
e0a953c3ee6040eaa9fae2b6...
紧凑存储(26字符)
B
{734fd453-a4f8-4c5d-...}
序列化
X
{0x3fa412e3,0x8356,...}
底层调试
csharp
复制代码
string guidStr = guid.ToString("N"); // 无连字符,节省28%存储空间
csharp
复制代码
Guid parsedGuid = Guid.Parse("9af7f46a-ea52-4aa3-b8c3-9fd484c2af12");
// 安全解析(避免异常)
if (Guid.TryParse("invalid-guid", out Guid safeGuid)) { ... }
复制代码
- 字节数组转换
csharp
复制代码
byte[] bytes = guid.ToByteArray();
Guid fromBytes = new Guid(bytes); // 从字节数组还原
(2)注意事项
版本
特点
推荐场景
V4
完全随机,全局唯一
通用标识、临时令牌
V7
时间戳前缀,局部有序
数据库主键(减少索引碎片)
V1/V2
含MAC地址,隐私风险
已弃用
csharp
复制代码
// ❌ 错误:每次循环新建实例可能导致重复(间隔<15ms时)
for (int i=0; i<1000; i++)
{
var g = Guid.NewGuid();
}
// ✅ 正确:复用单例
static readonly GuidGenerator = new Random();
Guid[] guids = Enumerable.Repeat(0, 1000).Select(_ => Guid.NewGuid()).ToArray();
存储优化
数据库字段 → 使用 uniqueidentifier
类型(SQL Server)
频繁传输 → 采用 N
格式字符串(26字符)
多线程安全
.NET 6+:无需额外处理,Guid.NewGuid()
内部线程安全
旧版本:通过 ThreadLocal
隔离实例
csharp
复制代码
private static ThreadLocal<Random> _threadRand =
new ThreadLocal<Random>(() => new Random(Guid.NewGuid().GetHashCode()));
(3)高级技巧
csharp
复制代码
public class Order
{
public Guid Id { get; } = Guid.CreateVersion7(); // .NET 9+
public string Product { get; set; }
}
csharp
复制代码
string tempFile = $"{Guid.NewGuid():N}.tmp"; // 生成唯一文件名
Directory.CreateDirectory($"uploads/{Guid.NewGuid()}");
csharp
复制代码
using System.Security.Cryptography;
byte[] cryptoBytes = new byte[16];
RandomNumberGenerator.Fill(cryptoBytes); // 真随机数
Guid secureGuid = new Guid(cryptoBytes);
(4)最佳实践
场景
推荐方案
原因
数据库主键
Guid.CreateVersion7()
(NET9+)
时序性减少索引碎片
高频生成标识符
静态单例 Guid.NewGuid()
避免实例化开销
网络传输/存储
ToString("N")
节省空间(26字符 vs 36字符)
加密安全需求
RandomNumberGenerator
+ Guid
构造
真随机性保障
历史代码兼容
Guid.Parse()
+ 格式校验
防止无效输入导致崩溃
9、Stopwatch
(1)核心功能
csharp
复制代码
Stopwatch stopwatch = new Stopwatch(); // 创建实例
stopwatch.Start(); // 启动计时
// 执行待测代码(如数据库查询、算法等)
stopwatch.Stop(); // 停止计时
TimeSpan elapsed = stopwatch.Elapsed; // 获取时间间隔
Console.WriteLine($"耗时:{elapsed.TotalMilliseconds}ms");
csharp
复制代码
// 一行代码完成计时
TimeSpan elapsed = Stopwatch.StartNew(() => {
// 待测代码
}).Elapsed;
(2)注意事项
csharp
复制代码
for (int i = 0; i < 10; i++) {
Stopwatch sw = new Stopwatch(); // 可能因种子相同导致时间值重复
sw.Start();
// ...
}
复制代码
- 正确做法(复用静态实例):
csharp
复制代码
static Stopwatch sw = new Stopwatch(); // 类级静态对象
for (int i = 0; i < 10; i++) {
sw.Restart(); // 重置并启动
// ...
sw.Stop();
}
场景
方案
.NET 6+
直接使用线程安全的 Stopwatch.StartNew()
旧版本.NET
为每个线程分配独立实例:new ThreadLocal<Random>(() => new Stopwatch())
精度与局限性
最高精度:依赖硬件支持,通常为 100纳秒级(通过 Stopwatch.IsHighResolution
检测)。
不适用场景:加密、安全相关操作(需改用 RNGCryptoServiceProvider
)。
(3)高级技巧
csharp
复制代码
Stopwatch sw = Stopwatch.StartNew();
MethodA();
sw.Stop();
TimeSpan timeA = sw.Elapsed;
sw.Restart(); // 重置计时器
MethodB();
sw.Stop();
TimeSpan timeB = sw.Elapsed;
csharp
复制代码
var timings = new List<long>();
for (int i = 0; i < 100; i++) {
sw.Restart();
// 执行代码
sw.Stop();
timings.Add(sw.ElapsedTicks); // 记录每次耗时(高精度)
}
double avgTicks = timings.Average();
csharp
复制代码
using (SqlConnection conn = new SqlConnection(connStr)) {
conn.Open();
Stopwatch sw = Stopwatch.StartNew();
// 执行查询
var data = conn.Query("SELECT * FROM LargeTable");
sw.Stop();
Log($"查询耗时:{sw.ElapsedMilliseconds}ms");
}
(4)场景优化
场景
推荐实践
短时操作测量
多次运行取平均值(避免单次误差)
Web API响应监控
在中间件中集成Stopwatch,记录接口耗时
算法效率对比
结合GC.Collect()
和GC.WaitForPendingFinalizers()
排除GC干扰
高频调用代码分析
使用ElapsedTicks
替代毫秒计数(更高精度)