内插字符串的原始类型是什么? [英] What is the original type of interpolated string?
问题描述
MSDN docs 包含有关隐式转换的部分:
MSDN docs contain the section about implicit conversions:
var s = $"hello, {name}";
System.IFormattable s = $"Hello, {name}";
System.FormattableString s = $"Hello, {name}";
从第一个字符串开始,内插字符串的原始类型是string
.好的,我可以理解,但是……我意识到字符串没有实现 IFormattable
.所以它看起来像是来自编译器的某种魔法,类似于它对 lambda 的作用.
From the first string it follows that original type of interpolated string is string
. Ok, I can understand it, but then… I realize that string does not implement IFormattable
. So it looks like some magic from the compiler similar to what it does with lambdas.
现在猜猜这段代码的输出:
Now guess the output of this code:
void Main()
{
PrintMe("Hello World");
PrintMe($"{ "Hello World"}");
}
void PrintMe(object message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
//void PrintMe(string message)
//{
// Console.WriteLine("I am a string " + message.GetType().FullName);
//}
void PrintMe(IFormattable message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
提示:
我是一个 System.String
我是一个System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
I am a System.String
I am a System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
如果您从第二种方法中删除评论,您将得到:
If you remove comments from the second method you'll get:
我是一个字符串 System.String
我是一个字符串 System.String
I am a string System.String
I am a string System.String
好的
可能是我不太了解重载解析,但是 C# 规范 意味着首先定义传递参数的类型,但 lambda 又是如何工作的?
Ok
May be I do not understand well overloading resolution, but 14.4.2 of C# spec implies that the type of the passed parameter is defined first, but again how do then lambdas work?
void Main()
{
PrintMe(() => {});
PrintMe(() => {});
}
void PrintMe(object doIt)
{
Console.WriteLine("I am an object");
}
//void PrintMe(Expression<Action> doIt)
//{
// Console.WriteLine("I am an Expression");
//}
void PrintMe(Action doIt)
{
Console.WriteLine("I am a Delegate");
}
删除评论和...
CS0121 以下方法之间的调用不明确或属性:'UserQuery.PrintMe(Expression)' 和'UserQuery.PrintMe(Action)'
CS0121 The call is ambiguous between the following methods or properties: 'UserQuery.PrintMe(Expression)' and 'UserQuery.PrintMe(Action)'
所以我不理解这里编译器的行为.
So I do not understand compiler's behavior here.
更新:
更糟糕的是,我检查了扩展方法的这种行为:
To make things worse I've checked this behavior for extension methods:
void Main()
{
PrintMe("Hello World");
PrintMe($"{"Hello World"}");
"Hello World".PrintMe();
$"{"Hello World"}".PrintMe();
}
void PrintMe(object message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
void PrintMe(IFormattable message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
public static class Extensions
{
public static void PrintMe(this object message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
public static void PrintMe(this IFormattable message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
}
现在我是这样的:
我是一个 System.String
我是 System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
我是一个 System.String
我是一个 System.String
I am a System.String
I am a System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
I am a System.String
I am a System.String
推荐答案
长话短说:
如果编译器找到带有 string
参数的方法 PrintMe
,它会生成此代码:
If the compiler finds a method PrintMe
with string
parameter it generates this code:
this.PrintMe("Hello World");
this.PrintMe(string.Format("{0}", "Hello World"));
如果您使用 string
参数注释方法 PrintMe
,它会生成此代码:
If you comment the method PrintMe
with string
parameter, it generates this code:
this.PrintMe("Hello World");
this.PrintMe(FormattableStringFactory.Create("{0}", new object[] {"Hello World"}));
然后,我猜方法重载决策的部分很容易.
Then, the part of method overload decision is pretty easy i guess.
this.PrintMe("Hello World");
选择object
参数方法,因为"Hello World"
不能隐式转换到 IFormattable
.
this.PrintMe("Hello World");
choose object
parameter method, since "Hello World"
can't be implicitly converted to IFormattable
.
这是基于编译器的决定:
This is based on the compiler's decision:
var s1 = $"{ "Hello World"}";
生成(作为最佳选择):
Generates (as a best option):
string s1 = string.Format("{0}", "Hello World");
还有:
void PrintMe(IFormattable message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
PrintMe($"{ "Hello World"}");
生成(为了匹配方法签名):
Generates (in order to match the method signature):
this.PrintMe(FormattableStringFactory.Create("{0}", new object[] {"Hello World"}));
对于扩展方法:
$"{"Hello World"}".PrintMe();
public static class Extensions
{
public static void PrintMe(this object message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
public static void PrintMe(this IFormattable message)
{
Console.WriteLine("I am a " + message.GetType().FullName);
}
}
编译器首先解析 $"{"Hello World"}"
,这会导致 string
作为最佳决策,然后检查是否存在方法 PrintMe()
找到(它被找到是因为字符串是一个 object
).所以生成的代码是:
The compiler resolves $"{"Hello World"}"
first, which leads to a string
as a best decision and then checks if there is a method PrintMe()
found (It is found since string is an object
). So the generated code is:
string.Format("{0}", "Hello World").PrintMe();
注意,如果您删除 object
的扩展方法,您将收到编译时错误.
Note that if you remove the extension method for object
, you'll get a compile-time error.
这篇关于内插字符串的原始类型是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!