为何无法将内插字符串直接赋值给继承IFormattable的自定义类?
解决自定义类无法直接接收插值字符串赋值的问题
问题原因
C# 中插值字符串($"")的类型转换有严格的内置规则:
- 当目标类型是
string时,编译器直接生成拼接后的字符串; - 当目标类型是
FormattableString或IFormattable时,编译器会生成FormattableString实例(因为FormattableString本身实现了IFormattable接口); - 对于自定义类型,哪怕实现了
IFormattable,编译器也不会自动将插值字符串转换为该类型——因为没有对应的内置转换逻辑,且C#不允许重载赋值运算符(=)。
另外,FormattableString是抽象类且构造函数为内部可见,无法通过继承它来让自定义类直接接收插值字符串。
解决方案
通过添加从FormattableString到自定义类的隐式转换运算符,让编译器先将插值字符串转为FormattableString,再自动转换为自定义类实例。同时保留原始格式化信息,方便后续本地化等场景使用。
修改后的代码示例:
public class Program { public static void Main() { IFormattable string1 = $"{1}, {"test"}"; // 正常工作 FormattableString string2 = $"{1}, {"test"}"; // 正常工作 LocStr string3 = $"{1}, {"test"}"; // 现在可正常赋值 } public class LocStr : IFormattable { private readonly FormattableString _formattableContent; // 接收FormattableString的构造函数,保存原始格式化信息 public LocStr(FormattableString formattableContent) { _formattableContent = formattableContent; } // 实现IFormattable接口,可在此添加本地化逻辑 public string ToString(string format, IFormatProvider formatProvider) { // 示例:根据传入的格式提供器格式化字符串 return _formattableContent.ToString(formatProvider); } // 重写默认ToString方法 public override string ToString() { return _formattableContent.ToString(); } // 隐式转换运算符:将FormattableString转为LocStr public static implicit operator LocStr(FormattableString fs) { return new LocStr(fs); } } }
补充说明
- 隐式转换是核心,它告知编译器如何将
FormattableString(插值字符串的默认转换类型之一)转为自定义类; - 保存
FormattableString可以保留原始的格式模板和参数,这对本地化场景至关重要——比如后续可以根据不同区域设置重新生成本地化字符串; - 如果不需要保留格式化参数,也可以添加从
string到LocStr的隐式转换,但这种方式会丢失插值信息,仅适用于简单场景。
内容的提问来源于stack exchange,提问作者osman doluca
相关产品推荐
相关产品推荐

