我基本上想要 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")
变得模棱两可?CS0121 The call is ambiguous between the following methods or properties: Test.Log(StringIfNotFormattableStringAdapter)' and 'Test.Log(FormattableString)'`
最佳答案
根据 C# 规范,Interpolated strings ,存在从内插字符串到 FormattableString
的隐式转换:
An interpolated_string_expression is classified as a value. If it is immediately converted to
System.IFormattable
orSystem.FormattableString
with an implicit interpolated string conversion (Implicit interpolated string conversions), the interpolated string expression has that type. Otherwise, it has the typestring
.
在提供的代码中还有
string
的转换至 StringIfNotFormattableStringAdapter
.方法调用
Log($"Hello");
都可以解析为
Log
方法,因为内插字符串表达式 $"Hello"
可:FormattableString
作为内插字符串; StringIfNotFormattableStringAdapter
如 string
. 这里编译器出现歧义,它需要额外的规则来解决这种歧义。为了解决歧义,编译器使用 C# 规范中描述的规则,Better Conversion Target (go to the bottom of the page 164) .规则是这样说的:
Given two different types
T1
andT2
,T1
is a better conversion target thanT2
if no implicit conversion fromT2
toT1
exists, and at least one of the following holds:
An implicit conversion from
T1
toT2
exists(other rules are not important for our case)
在提供的代码中
FormattableString
比 StringIfNotFormattableStringAdapter
更好的转换因为StringIfNotFormattableStringAdapter
的隐式转换至 FormattableString
和
FormattableString
的隐式转换至 StringIfNotFormattableStringAdapter
存在。 因此编译器更喜欢转换内插字符串
$"Hello"
至 FormattableString
然后调用方法 Log(FormattableString)
.Why does removing the
implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)
cause the call
Log($"Hello")
to become ambiguous?
因为当您删除此运算符时,第二条规则(“存在从
FormattableString
到 StringIfNotFormattableStringAdapter
的隐式转换存在”)中断,现在编译器无法定义更好的转换目标。这会导致编译器产生歧义并发生编译错误。
关于c# - 使用隐式转换重载解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60778208/