为什么字符串插值喜欢使用string而不是IFormattable的方法过载
设想如下:
static class Log {
static void Debug(string message);
static void Debug(IFormattable message);
static bool IsDebugEnabled { get; }
}我有一些ToString()很贵的东西。在此之前,我做了以下工作:
if (Log.IsDebugEnabled) Log.Debug(string.Format("Message {0}", expensiveObject));现在,我希望IsDebugEnabled逻辑在Debug(IFormattable)中,并且只在必要时对消息中的对象调用ToString()。
Log.Debug($"Message {expensiveObject}");然而,这就调用了Debug(string)重载。
发布于 2016-03-03 11:27:21
这是一个罗斯林团队深思熟虑的决定
我们通常认为,对于执行不同任务的方法,库大多会使用不同的API名称编写。因此,FormattableString和String之间的重载解决方案差异并不重要,所以字符串可能也会赢。因此,我们应该坚持一个简单的原则,即插值字符串就是字符串。故事到此结束。
链接中对此有更多的讨论,但结果是他们希望您使用不同的方法名称。
一些库API确实希望消费者使用FormattableString,因为它更安全或更快。接受字符串的API和使用FormattableString的API实际上做了不同的事情,因此不应该在相同的名称上重载。
发布于 2016-08-19 09:14:22
当你意识到你为什么不能这么做的时候,我只想指出,事实上你可以做到这一点。
您只需要欺骗编译器,使它更喜欢FormattableString重载。我已经在这里详细解释过了:https://robertengdahl.blogspot.com/2016/08/how-to-overload-string-and.html
下面是测试代码:
public class StringIfNotFormattableStringAdapterTest
{
public interface IStringOrFormattableStringOverload
{
void Overload(StringIfNotFormattableStringAdapter s);
void Overload(FormattableString s);
}
private readonly IStringOrFormattableStringOverload _stringOrFormattableStringOverload =
Substitute.For<IStringOrFormattableStringOverload>();
public interface IStringOrFormattableStringNoOverload
{
void NoOverload(StringIfNotFormattableStringAdapter s);
}
private readonly IStringOrFormattableStringNoOverload _noOverload =
Substitute.For<IStringOrFormattableStringNoOverload>();
[Fact]
public void A_Literal_String_Interpolation_Hits_FormattableString_Overload()
{
_stringOrFormattableStringOverload.Overload($"formattable string");
_stringOrFormattableStringOverload.Received().Overload(Arg.Any<FormattableString>());
}
[Fact]
public void A_String_Hits_StringIfNotFormattableStringAdapter_Overload()
{
_stringOrFormattableStringOverload.Overload("plain string");
_stringOrFormattableStringOverload.Received().Overload(Arg.Any<StringIfNotFormattableStringAdapter>());
}
[Fact]
public void An_Explicit_FormattableString_Detects_Missing_FormattableString_Overload()
{
Assert.Throws<InvalidOperationException>(
() => _noOverload.NoOverload((FormattableString) $"this is not allowed"));
}
}下面是使这一工作有效的代码:
public class StringIfNotFormattableStringAdapter
{
public string String { get; }
public StringIfNotFormattableStringAdapter(string s)
{
String = s;
}
public static implicit operator StringIfNotFormattableStringAdapter(string s)
{
return new StringIfNotFormattableStringAdapter(s);
}
public static implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)
{
throw new InvalidOperationException(
"Missing FormattableString overload of method taking this type as argument");
}
}发布于 2020-02-26 12:16:46
您不能强迫编译器在字符串上选择IFormattable/FormattableString,但是可以使它选择IFormattable/FormattableString而不是Object:
static class Log
{
static void Debug(object message);
static void Debug(IFormattable message);
static void Debug(FormattableString message);
static bool IsDebugEnabled { get; }
}该解决方案的成本是接受对象的方法中的一个额外的ToString()-call。(对于FormattableString来说,额外的重载并不是必要的,但是可以简化使用内插条纹的位置的查找)
https://stackoverflow.com/questions/35770713
复制相似问题