You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#异常消息与性能优化:未抛出异常时是否仍会创建消息字符串?

关于循环内异常消息性能开销的问题

我知道这看起来像是微优化,但我要运行数千万次循环,性能是核心关键问题。每次循环里都会执行如下检查:

if (this.isSafeMode && bar.Period != this.SourcePeriod)
{
    throw new InvalidOperationException(
        "Attempted to process a bar that does not match the market context's source period. " +
        $"Processed bar period: [{bar.Period}] " +
        $"Market context source period: [{this.SourcePeriod}]");
}

问题1

即使没有抛出异常,每次循环都会创建这个异常消息字符串,从而产生不必要的性能开销吗?(其他场景里我需要构建开销更大的异常消息,这里只是简单示例)

问题2

如果问题1的答案是肯定的,创建一个能接收参数、并根据参数构建消息字符串的自定义异常类型,能不能避免这种不必要的开销?或者有没有其他替代方案?

补充说明:该异常不需要适配多语言翻译(如果有这个需求的话,自定义异常会更合理)


回答

问题1的答案

是,即使不抛出异常,你当前的写法也会产生不必要的性能开销。因为C#的字符串插值($"")和字符串拼接操作,会在throw语句执行前就完成——只要进入if条件判断的代码路径,不管最终会不会抛出异常,这些字符串构建工作都会先执行。在数千万次循环的场景下,这种累积的开销会非常明显。

问题2的解决方案

方案1:延迟构建异常消息(自定义异常)

自定义异常确实能解决这个问题。你可以把需要的参数(比如bar.Period和SourcePeriod)传入自定义异常的构造函数,然后重写Message属性,只在需要获取异常消息的时候才拼接字符串。这样只有当异常真的被抛出、且消息被访问时,才会执行字符串构建操作,完全避免无异常时的额外开销。

示例代码:

public class MismatchedBarPeriodException : InvalidOperationException
{
    private readonly string _processedPeriod;
    private readonly string _sourcePeriod;

    public MismatchedBarPeriodException(string processedPeriod, string sourcePeriod)
    {
        _processedPeriod = processedPeriod;
        _sourcePeriod = sourcePeriod;
    }

    public override string Message
    {
        get
        {
            return $"Attempted to process a bar that does not match the market context's source period. Processed bar period: [{_processedPeriod}] Market context source period: [{_sourcePeriod}]";
        }
    }
}

循环内的调用代码改为:

if (this.isSafeMode && bar.Period != this.SourcePeriod)
{
    throw new MismatchedBarPeriodException(bar.Period.ToString(), this.SourcePeriod.ToString());
}

方案2:轻量替代——延迟字符串构建

如果不想自定义异常,也可以把字符串拼接逻辑封装成单独方法,仅在确定要抛出异常时才调用:

private string GetMismatchedPeriodMessage(string processedPeriod, string sourcePeriod)
{
    return $"Attempted to process a bar that does not match the market context's source period. Processed bar period: [{processedPeriod}] Market context source period: [{sourcePeriod}]";
}

// 循环内代码
if (this.isSafeMode && bar.Period != this.SourcePeriod)
{
    throw new InvalidOperationException(GetMismatchedPeriodMessage(bar.Period.ToString(), this.SourcePeriod.ToString()));
}

这种方式同样能保证只有if条件成立时,才会执行字符串构建,无异常时不会产生额外开销。

方案3:极致优化(参数类型固定时适用)

如果Period是枚举或有限固定值,可以提前缓存消息模板,用string.Format替换参数,减少重复的字符串拼接开销。不过这种场景下收益有限,前面两种方案已经足够解决核心问题。


内容的提问来源于stack exchange,提问作者Sean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:00:06