前篇文章里我谈了谈String.Concat与StringBuilder的实现,于是后来有个朋友回复到:“我发现StringBuilder里好像也用了String.Concat。在一次异常中,Exception的StackTrace显示是先发生了String.Concat异常,然后再StringBuilder.Append。”不过经过一些简单的分析,我们会发现StringBuilder.Append方法的各个重载都没有依赖(即调用)String.Concat方法,那么这样的调用堆栈又是如何形成的呢?
前篇文章里我谈了谈String.Concat与StringBuilder的实现,于是后来有个朋友回复到:“我发现StringBuilder里好像也用了String.Concat。在一次异常中,Exception的StackTrace显示是先发生了String.Concat异常,然后再StringBuilder.Append。”不过经过一些简单的分析,我们会发现StringBuilder.Append方法的各个重载都没有依赖(即调用)String.Concat方法,那么这样的调用堆栈又是如何形成的呢?
展开答案
其实这并不困难,只要简单“推理”一番便可。虽然StringBuilder的Append方法没有依赖String.Concat方法,但这只能说明Append方法没有直接调用String.Concat。然而,只要Append方法有机会调用到我们自定义的逻辑中,便可以由我们的逻辑调用Concat方法。这样的方法可以是Append(object)重载:
public StringBuilder Append(object value)
{
if (value == null)
{
return this;
}
return this.Append(value.ToString());
}
那么,我们的方法可以调用String.Concat方法,但又如何让它抛出异常呢?很容易,因为String.Concat方法也有个Concat(object, object)重载会调用参数的ToString方法。不过,如果我们直接调用String.Concat方法也太不自然了些,相信之前那位朋友也不会这么做。但是,其实我们完全可以:
public class InBuilder
{
public override string ToString()
{
return "Hello" + new InConcat();
}
}
public class InConcat
{
public override string ToString()
{
throw new Exception();
}
}
static void Main()
{
var builder = new StringBuilder();
builder.Append(new InBuilder());
}
看InBuilder的ToString中,将一个字符串与另一个非字符串对象连接起来,而这个连接操作便会被编译为String.Concat(object, object)方法:
.method public hidebysig virtual instance string ToString() cil managed
{
.maxstack 8
L_0000: ldstr "Hello"
L_0005: newobj instance void SimpleConsole.Program/InConcat::.ctor()
L_000a: call string [mscorlib]System.String::Concat(object, object)
L_000f: ret
}
于是执行Main方法便会抛出一个异常,它的StackTrace便是:
at SimpleConsole.Program.InConcat.ToString() in ...
at System.String.Concat(Object arg0, Object arg1)
at SimpleConsole.Program.InBuilder.ToString() in ...
at System.Text.StringBuilder.Append(Object value)
at SimpleConsole.Program.Main() in ...
...
嘿嘿,我是不是很无聊?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
2006-12-04 讲座展示:TechEd Europe DEV 411 - AJAX Patterns with ASP.NET AJAX(1)
2006-12-04 WPF/E Dev Center出现的过于仓促了
2006-12-04 文章推荐:ASP.NET AJAX Under the Hood Secrets及其他