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. 1

    为什么Text生成必须先决定最终Consumer

    同一个amount可能显示给用户、写入machine protocol、作为signature input或进入structured log。若过早变成plain string,typed value、format intent与culture owner都丢失。C 6 interpolation改…

  2. 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. 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。答案都是否。

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);
分步1 / 3

切换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要显式。

分步1 / 3

切换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));
分步1 / 3

切换argument、property、member与external schema

本章回顾:在最后负责的Boundary才生成Text

  1. Concatenation、composite、interpolation和structured logging保留的信息层级不同。
  2. Culture由consumer boundary拥有;UI、machine与canonical representation不能共用implicit default。
  3. FormattableString延迟formatting,不延迟argument expression,也不自动提供security。
  4. Modern handlers改变target/evaluation optimization,必须与原书C# 6语义分开。
  5. 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、分配计数或地址/修改轨迹核对复制、别名与边界。

资料与写作方式声明

本章以C# in Depth, Fourth Edition, Chapter 9: Stringy features权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…