内插字符串的原始类型是什么? [英] What is the original type of interpolated string?

查看:54
本文介绍了内插字符串的原始类型是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆