Chapter 9. Stringy features
覆盖.NET string formatting回顾、interpolated literals、FormattableString localization、使用限制与nameof,区分display、machine和external schema contract。
学习目标
- 能比较concatenation、composite formatting、interpolation与structured logging保留的template、type和culture信息
- 能设计string、FormattableString、IFormattable及modern handler边界,复现locale与evaluation差异
- 能判断nameof适合source diagnostics还是不适合external schema,验证rename与version compatibility
机制总览
Chapter 9. Stringy features:机制路径
- 1
为什么Text生成必须先决定最终Consumer
同一个amount可能显示给用户、写入machine protocol、作为signature input或进入structured log。若过早变成plain string,typed value、format intent与culture owner都丢失。C 6 interpolation改…
- 2
A recap on string formatting …
Concatenation逐个调用string conversion,template与values混在operations中;composite formatting用 0:N2 加object arguments,支持format provider但numeric indexes易错且value types可能boxing。
- 3
Introducing interpolated stri…
C 6 $"Order id : total:C2 " 把expressions、alignment与format specifier靠近label,compiler lowering在该版本通常等价于 string.Format /formatting calls。它仍按target string…
章级决策实验
Chapter 9. Stringy features:机制与证据
切换《Chapter 9. Stringy features》的三个关键教学阶段,先解释机制,再用运行与失败证据验证结论。
选择推理阶段
当前阶段 · 为什么Text生成必须先决定最终Consumer
同一个amount可能显示给用户、写入machine protocol、作为signature input或进入structured log。若过早变成plain string,typed value、format intent与culture owner都丢失。C 6 interpolation改…
可核验证据
以明确的 LangVersion 与目标框架构建「为什么Text生成必须先决定最终Consumer」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
学完《Chapter 9. Stringy features》后,应能从输入和前置条件推导状态变化,并用可重复的构建、运行或边界测试证明结果。
失效—证据矩阵
Chapter 9. Stringy features:失效与核验
为什么Text生成必须先决定最终Consumer
典型失效
若解释「为什么Text生成必须先决定最终Consumer」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「为什么Text生成必须先决定最终Consumer」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
A recap on string formatting …
典型失效
若解释「A recap on string formatting …」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「A recap on string formatting …」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
Introducing interpolated stri…
典型失效
若解释「Introducing interpolated stri…」时混淆语言规范、编译器降级、运行时和类库责任,版本变化后就会把实现细节误当作 C# 语义保证。
核验证据
以明确的 LangVersion 与目标框架构建「Introducing interpolated stri…」的正反案例,并用编译诊断、生成 IL、运行轨迹或分配数据核对实际边界。
为什么Text生成必须先决定最终Consumer
同一个amount可能显示给用户、写入machine protocol、作为signature input或进入structured log。若过早变成plain string,typed value、format intent与culture owner都丢失。C# 6 interpolation改善source readability,FormattableString保留晚格式化选择,nameof把symbol name从脆弱literal变成compiler-checked expression。
先预测:interpolated string是否永远使用InvariantCulture;FormattableString是否保留原C# expressions;nameof是否返回qualified path;预先插值后交给logger是否仍是structured field。答案都是否。
↡在value转text前明确display、machine、logging或protocol consumer,由该边界选择format与culture。A recap on string formatting in .NET
Concatenation逐个调用string conversion,template与values混在operations中;composite formatting用{0:N2}加object arguments,支持format provider但numeric indexes易错且value types可能boxing。IFormattable.ToString(format, provider)是value参与formatting的核心contract。
UI display使用用户culture;machine persistence、cache key和cryptographic canonicalization需要stable invariant/explicit encoding。Round-trip numeric/date通常用标准round-trip format或typed serializer,不能依赖current machine culture。
var display = amount.ToString("C", userCulture);
var protocol = amount.ToString("G29", CultureInfo.InvariantCulture);切换concatenation、composite、interpolation与logging
Introducing interpolated string literals
C# 6 $"Order {id}: {total:C2}"把expressions、alignment与format specifier靠近label,compiler lowering在该版本通常等价于string.Format/formatting calls。它仍按target string生成final text,并不自动localize surrounding words;translation system仍需resource template。
Interpolation expression只evaluate一次但遵循source order,可能有side effects或抛异常。不要把business actions放在format expression;先计算named values让fault与debug更清楚。
Modern C# 10 interpolated string handler允许target API控制evaluation与allocation,例如disabled logging可跳过formatted expressions。这是后续版本,不应倒写成C# 6 guarantee;target-typed behavior必须按实际overload测试。
Localization using FormattableString
当interpolation target是FormattableString,compiler构造format string与object arguments,sink稍后用ToString(provider)选择culture。它保留的是composite format和evaluated argument values,不是expression tree;side effects在construction时已发生。
FormattableString message = $"Total: {amount:N2} at {timestamp:O}";
string localized = message.ToString(userCulture);
string invariant = FormattableString.Invariant(message);API可接收FormattableString用于SQL-like builder,但绝不能把它当自动parameterization/security:必须由trusted implementation把arguments作为parameters,format text本身也需严格解析。Ordinary string overload与FormattableString overload并存时,target resolution可能选不同path,call-site要显式。
↡interpolation转换为composite format与已求值arguments,使最终sink稍后选择IFormatProvider。切换string、FormattableString、IFormattable与handler
Uses, guidelines, and limitations
选择string representation前问:是否需要localize words、是否需要round-trip、是否需structured fields、是否跨trust boundary。Display string可随culture变化;protocol string必须versioned/canonical;exception message用于human diagnosis但不能包含secret;user-visible text通常来自resource system。
Large/hot formatting需profile。StringBuilder适合多次append,Span/handlers适合measured low-allocation path;不要牺牲culture correctness和readability换未经证明的micro-optimization。Interpolated syntax本身不是performance guarantee。
Accessing identifiers with nameof
nameof(symbol)在compile time产生unqualified simple name string,同时compiler验证symbol。它适合argument exception paramName、property notification和diagnostic labels,rename refactor会更新binding。它不执行expression,也不返回runtime value或full path。
External JSON field、database column、metric name和wire command必须由external contract显式命名/version,不能用nameof跟着internal refactor静默改变。Likewise overloads共享same nameof result,若需要method identity还要signature/event id。
ArgumentNullException.ThrowIfNull(customer, nameof(customer));
OnPropertyChanged(nameof(Customer.Name));切换argument、property、member与external schema
本章回顾:在最后负责的Boundary才生成Text
- Concatenation、composite、interpolation和structured logging保留的信息层级不同。
- Culture由consumer boundary拥有;UI、machine与canonical representation不能共用implicit default。
- FormattableString延迟formatting,不延迟argument expression,也不自动提供security。
- Modern handlers改变target/evaluation optimization,必须与原书C# 6语义分开。
- nameof保护source-coupled names;external schema/name独立version,不能跟随internal rename。
练习
问题 1:金额同时用于UI、日志和签名,应怎样表示?
问题 2:FormattableString API如何避免被误当安全SQL?
问题 3:哪些name适合nameof,哪些不适合?
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- text consumer boundary
- deferred culture formatting
- symbol-name contract
- external name contract
- canonical representation
原版目录概念补充核对
以下条目补齐官方目录中容易被示例主线掩盖的概念。它们不重复罗列目录,而是明确每项概念的机制、适用边界和验收证据。
Introducing interpolated string literals:机制、边界与证据
Chapter 9. Stringy features中的Introducing interpolated string literals涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。
Localization using FormattableString:机制、边界与证据
Chapter 9. Stringy features中的Localization using FormattableString涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。
Uses, guidelines, and limitations:机制、边界与证据
Chapter 9. Stringy features中的Uses, guidelines, and limitations涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。
Accessing identifiers with nameof:机制、边界与证据
Chapter 9. Stringy features中的Accessing identifiers with nameof涉及值的存储位置、复制语义与生命周期,语法简洁不代表没有别名或逃逸限制。准备可编译和应被编译器拒绝的样本,结合 IL、分配计数或地址/修改轨迹核对复制、别名与边界。