我基本上希望string/FormattableString有两个单独的重载(背景是,我希望促使人们使用字符串常量来处理日志消息,并通过结构化日志记录传递参数,而不是通过日志消息来简化分析。因此,FormattableString日志记录方法将被淘汰)。
现在,由于编译器的工作方式,您不能直接重载方法,因为在传递字符串之前,FormattableString会转移到字符串中。但是,有一个定义隐式重载的包装器结构是可行的:
public struct StringIfNotFormattableStringAdapter
{
public string StringValue { get; }
private StringIfNotFormattableStringAdapter(string s)
{
StringValue = s;
}
public static implicit operator StringIfNotFormattableStringAdapter(string s)
{
return new StringIfNotFormattableStringAdapter(s);
}
public static implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)
{
throw new InvalidOperationException("This only exists to allow correct overload resolution. " +
"This should never be called since the FormattableString overload should be preferred to this.");
}
}
public static class Test
{
public static void Log(StringIfNotFormattableStringAdapter msg)
{
}
public static void Log(FormattableString msg)
{
}
public static void Foo()
{
Log("Hello"); // resolves to StringIfNotFormattableStringAdapter overload
Log($"Hello"); // resolves to FormattableString overload
}
}到目前一切尚好。
我不明白的是:为什么要移除
implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)导致调用Log($"Hello")变得模糊?
Test.Log(StringIfNotFormattableStringAdapter)‘和’Test.Log(FormattableString)‘’
发布于 2020-03-23 03:24:09
根据C#规范,内插字符串,有一个内插字符串到FormattableString的隐式转换
interpolated_string_expression被归类为值。如果立即使用隐式内插字符串转换(
System.IFormattable)将其转换为System.FormattableString或System.FormattableString,则内插字符串表达式具有该类型。否则,它具有string类型。
在所提供的代码中,还可以将string转换为StringIfNotFormattableStringAdapter。
方法调用
Log($"Hello");可以解析为两个Log方法,因为内插字符串表达式$"Hello"可以是:
FormattableString作为内插字符串;StringIfNotFormattableStringAdapter作为string。在这里,编译器出现了一种矛盾,需要额外的规则来解决这种歧义。要解决歧义编译器使用C#规范、更好的转换目标(转到第164页的底部)中描述的规则。规则规定:
给定两种不同类型的
T1和T2,如果不存在从T2到T1的隐式转换,则T1是比T2更好的转换目标,并且至少有以下一种情况:
T1到T2的隐式转换存在在提供的代码中,FormattableString比StringIfNotFormattableStringAdapter更好的转换,因为
StringIfNotFormattableStringAdapter到FormattableString的隐式转换。和
FormattableString到StringIfNotFormattableStringAdapter的隐式转换。因此,编译器倾向于将插值的字符串$"Hello"转换为FormattableString,然后调用方法Log(FormattableString)。
为什么要删除 隐式运算符StringIfNotFormattableStringAdapter(FormattableString fs) 导致调用
Log($"Hello")变得模糊?
因为当您删除此操作符时,第二条规则(“存在从FormattableString到StringIfNotFormattableStringAdapter的隐式转换”)中断,现在编译器无法定义更好的转换目标。这会导致编译器出现歧义,并出现编译错误。
https://stackoverflow.com/questions/60778208
复制相似问题