具有布尔格式的字符串插值
如何为布尔值指定与其他类型的其他格式字符串一致的格式字符串?
给出以下代码:
double d = Math.PI;
DateTime now = DateTime.Now;
bool isPartyTime = true;
string result = $"{d:0.0}, {now:HH:mm}, time to party? {isPartyTime}";
我可以为每个基本类型指定一种格式,除了 bool
之外。我知道我可以这样做:
string result = $"{d:0.0}, {now:HH:mm}, time to party? {(isPartyTime ? "yes!" : "no")}";
但这仍然与其他类型不一致。
有没有一种方法可以使插值字符串中的布尔值保持一致?
PS我确实搜索了包含此链接的答案:
https://stackoverflow.com/questions/tagged /c%23+string-interpolation+boolean
令人惊讶的是结果为零。
How can I specify a format string for a boolean that's consistent with the other format strings for other types?
Given the following code:
double d = Math.PI;
DateTime now = DateTime.Now;
bool isPartyTime = true;
string result = quot;{d:0.0}, {now:HH:mm}, time to party? {isPartyTime}";
I can specify a format for every primitive type, except for bool
it seems. I know I can do:
string result = quot;{d:0.0}, {now:HH:mm}, time to party? {(isPartyTime ? "yes!" : "no")}";
However this is still inconsistent with the other types.
Is there a way of formatting booleans in interpolated strings that is consistent?
P.S. I did search for an answer including this link:
https://stackoverflow.com/questions/tagged/c%23+string-interpolation+boolean
And surprisingly had zero results.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,不,没有。
根据 Microsoft ,具有格式字符串的唯一数据类型是:
DateTime, DateTimeOffset
)System.Enum
派生的所有类型)BigInteger、Byte、Decimal、Double、Int16、Int32、Int64、SByte、Single、UInt16、UInt32、UInt64
)Guid
TimeSpan
Boolean.ToString() 只能返回“True”或“False”。它甚至说,如果需要将其写入 XML,则需要手动执行
ToLowerCase()
(由于缺乏字符串格式)。Unfortunately, no, there isn't.
According to Microsoft, the only data types with format strings are:
DateTime, DateTimeOffset
)System.Enum
)BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64
)Guid
TimeSpan
Boolean.ToString() can only return "True" or "False". It even says, if you need to write it to XML, you need to manually perform
ToLowerCase()
(from the lack of string formatting).使用 C# 10.0?只需使用字符串插值处理程序
自定义字符串插值处理程序记录在此处 和 这里
(我还没有任何 C# 10.0 功能的经验,但我将来会扩展这一部分 - 现在我仍然停留在 C# 上7.3 土地,因为我的日常工作项目依赖于 .NET Framework 4.8)
使用 C# 1.0 到 C# 9.0?
快速修复:
Boolean
包装结构如果您控制字符串格式调用站点,则只需更改要使用的
bool
/Boolean
类型的值相反,可隐式转换的零开销值类型,例如:因此您的示例调用站点变为:
并且
结果
将是“3.1,21:03,聚会时间到了?是”
气泡破裂:不,你不能覆盖
Boolean.TrueString
和FalseString
因为
Boolean
的static readonly String TrueString = "True";
也被标记为initonly
你不能使用反射覆盖它,所以这样做:...会给你一个运行时异常:
通过操纵原始内存仍然是可能的,但这超出了这个问题的范围。
使用
IFormatProvider
和ICustomFormatter
:始终可以覆盖
String.Format
和内插字符串的方式(例如$"Hello, { world}"
) 通过提供自定义的IFormatProvider
进行格式化;尽管String.Format
通过公开Format
重载参数可以轻松实现这一点,但插值字符串却不然,相反,它会迫使您在某种程度上丑化您的代码。formatType
参数之一调用IFormatProvider.GetFormat(Type)
:typeof(DateTimeFormatInfo)
typeof(NumberFormatInfo)
typeof(ICustomFormatter)
typeof()
类型被传递到GetFormat
(至少就 ILSpy 和 RedGate 而言)反射器告诉我)。魔法发生在
ICustomFormatter.Format
内部,并且实现它很简单:...所以只需以某种方式将
MyCustomFormatProvider.Instance
传递到String.Format
中,就像以下。这适用于
String.Format
,但是我们如何将MyCustomFormatProvider
与 C#$""
内插字符串一起使用...?...非常困难,因为设计插值字符串功能的 C# 语言团队使其始终传递
provider: null
,因此所有值都使用他们的默认(通常是特定于文化的)格式,并且他们没有提供任何方法来轻松指定自定义IFormatProvider
,即使有数十年历史的静态代码分析反对隐式使用CurrentCulture< 的规则/code>
(尽管微软打破自己的规则并不罕见......)。
CultureInfo.CurrentCulture
不起作用,因为Boolean.ToString()
根本不使用CultureInfo
。困难源于 C#
$""
内插字符串 始终隐式转换为String
(即立即格式化)除非$""
字符串表达式被直接分配给一个变量或参数输入为FormattableString
或IFormattable
,但令人愤怒 这不会扩展到扩展方法(因此public static String MyFormat( this FormattableString fs, ... )
不起作用。 唯一这里可以做的就是调用
String MyFormat( this FormattableString fs, ... )
方法作为(语法上“正常”)静态方法调用,不过使用using static MyFormattableStringExtensions
在某种程度上减少了人体工程学问题 - 如果您使用全局使用(这需要 C# 10.0,它已经支持自定义插值字符串处理程序,所以这有点没有实际意义)。但像这样:
并像这样使用:
或者只是改变
FormattableString
的参数数组MyFmt( $"" )< /code> 上面),有一个更简单的替代方法来实现
IFormatProvider
和ICustomFormatter
:只需编辑FormattableString
的值参数数组 直接地。String.Format(IFormatProvider, String format, ...)
中格式化Boolean
值,则更可取。并像以前一样使用以获得相同的结果:
Using C# 10.0? Just use a String Interpolation Handler
Custom String Interpolation Handlers are documented here and here
(I don't have any experience with any C# 10.0 features yet, but I'll expand this section in future - right now I'm still stuck in C# 7.3 land due to my day-job's projects' dependencies on .NET Framework 4.8)
Using C# 1.0 through C# 9.0?
Quick-fix:
Boolean
wrapper structIf you control the string-formatting call-sites, then just change
bool
/Boolean
-typed values to use an implicitly-convertible zero-overhead value-type instead, e.g.:So your example call-site becomes:
And
result
will be"3.1, 21:03, time to party? Yes"
Bubble-bursting: No, you can't overwrite
Boolean.TrueString
andFalseString
Because
Boolean
'sstatic readonly String TrueString = "True";
is also marked withinitonly
you cannot overwrite it using reflection, so doing this:...will give you a runtime exception:
It is still possible by manipulating raw memory, but that's out-of-scope for this question.
Using
IFormatProvider
andICustomFormatter
:It's always been possible to override how both
String.Format
and interpolated strings (e.g.$"Hello, {world}"
) are formatted by providing a customIFormatProvider
; though whileString.Format
makes it easy by exposing aFormat
overload parameter, interpolated strings do not, instead it forces you to uglify your code somewhat.IFormatProvider
is (still) surprisingly underdocumented in .NET.IFormatProvider.GetFormat(Type)
is only ever invoked with one of these 3formatType
arguments:typeof(DateTimeFormatInfo)
typeof(NumberFormatInfo)
typeof(ICustomFormatter)
typeof()
types are passed intoGetFormat
(at least as far as ILSpy and RedGate Reflector tell me).The magic happens inside
ICustomFormatter.Format
and implementing it is straightforward:...so just pass
MyCustomFormatProvider.Instance
intoString.Format
somehow, like below.So that works for
String.Format
, but how can we useMyCustomFormatProvider
with C#$""
interpolated strings...?...with great difficulty, because the C# langauge team who designed the interpolated strings feature made it always pass
provider: null
so all values use their default (usually Culture-specific) formatting, and they didn't provide any way to easily specify a customIFormatProvider
, even though there's decades-old Static Code Analysis rule against relying on implicit use ofCurrentCulture
(though it's not uncommon for Microsoft to break their own rules...).CultureInfo.CurrentCulture
won't work becauseBoolean.ToString()
doesn't useCultureInfo
at all.The difficulty stems from the fact that C#
$""
interpolated strings are always implicitly converted toString
(i.e. they're formatted immediately) unless the$""
string expression is directly assigned to a variable or parameter typed asFormattableString
orIFormattable
, but infuriatingly this does not extend to extension methods (sopublic static String MyFormat( this FormattableString fs, ... )
won't work.The the only thing that can be done here is to invoke that
String MyFormat( this FormattableString fs, ... )
method as a (syntactically "normal") static method call, though usingusing static MyFormattableStringExtensions
somewhat reduces the ergonomics problems - even more-so if you use global-usings (which requires C# 10.0, which already supports custom interpolated-string handlers, so that's kinda moot).But like this:
And used like this:
Or just mutate
FormattableString
's arguments arrayMyFmt( $"" )
above), there's a simpler alternative approach to having to implementIFormatProvider
andICustomFormatter
: just edit theFormattableString
's value arguments array directly.Boolean
values inString.Format(IFormatProvider, String format, ...)
.And used just like before to get the same results:
这可能是显而易见的,但为了减少重复,您始终可以创建一个扩展方法。它至少能让你成功一半。
This may be obvious but to cut down the repetition, you could always create an extension method. It gets you half way there at least.