C# string.Format上的{{{0}}做什么?
在命名空间C# string.Format上的{{{0}}做什么?,c#,lazy-evaluation,C#,Lazy Evaluation,在命名空间MS.Internal中,有一个名为NamedObject的类 它有一个奇怪的代码块: public override string ToString() { if (_name[0] != '{') { // lazily add {} around the name, to avoid allocating a string // until it's actually needed _name = String.Format(CultureInf
MS.Internal
中,有一个名为NamedObject
的类
它有一个奇怪的代码块:
public override string ToString()
{
if (_name[0] != '{')
{
// lazily add {} around the name, to avoid allocating a string
// until it's actually needed
_name = String.Format(CultureInfo.InvariantCulture, "{{{0}}}", _name);
}
return _name;
}
我对这一评论特别好奇:
// lazily add {} around the name, to avoid allocating a string
// until it's actually needed
_name = String.Format(CultureInfo.InvariantCulture, "{{{0}}}", _name);
那怎么会是“懒惰”?懒惰有什么用
从以下位置开始的完整类:
/--------------------------------------------------------------
//
//
//版权所有(C)微软公司。版权所有。
//
//
//描述:占位符对象,其名称显示在调试器中
//
//---------------------------------------------------------------------------
使用制度;
利用制度全球化;
使用MS.Internal.WindowsBase;
名称空间MS.Internal
{
///
///该类的实例可以在您可能使用的任何地方使用
///“new Object()”。该名称将显示在调试器中,而不是
///仅仅是“{object}”
///
[FriendAccessAllowed]//内置在Base中,也由Framework使用。
内部类NamedObject
{
公共名称对象(字符串名称)
{
if(String.IsNullOrEmpty(name))
抛出新的ArgumentNullException(名称);
_名称=名称;
}
公共重写字符串ToString()
{
如果(_name[0]!='{')
{
//在名称周围延迟添加{},以避免分配字符串
//直到真正需要它
_name=String.Format(CultureInfo.InvariantCulture,“{{{0}}}”,_name);
}
返回_name;
}
字符串\u名称;
}
}
//提供的文件仅供Microsoft Corporation(c)2007参考。
//版权所有(c)微软公司。保留所有权利。
你,即{
产生{
,而}
产生}
中间的<代码> { 0 } /COD>被解释为通常-即引用索引为零的参数。
{{ {0} }}
^^ ^^^ ^^
| | |
| | +--- Closing curly brace
| +------ Parameter reference
+---------- Opening curly brace
最终结果是用大括号括起来的参数零的值:
var res = string.Format("{{{0}}}", "hello"); // produces {hello}
那怎么会是“懒惰”
他们称之为懒惰,因为这是另一种“渴望”的实现方式:
internal class NamedObject {
public NamedObject(string name) {
if (String.IsNullOrEmpty(name))
throw new ArgumentNullException(name);
if (name[0] != '{') {
// eagerly add {} around the name
_name = String.Format(CultureInfo.InvariantCulture, "{{{0}}}", name);
} else {
_name = name;
}
}
public override string ToString() {
return _name;
}
string _name;
}
此实现立即添加大括号,即使它不知道需要大括号中包含的名称。{{
和}
只需给您文本{
和}
(转义大括号)
因此,如果您有{{{0}}
,并且您提供foo
,那么输出将是{foo}
var value = "value";
String.Format(CultureInfo.InvariantCulture, "{{{0}}}", value); // will output {value}
“懒惰”是怎么回事?懒惰是怎么回事
懒惰来自于它前面的if(_name[0]!='{')
它仅在第一次请求时更改\u name
字段
正如大家已经指出的,String.Format({{{{0}}},{u name)
应该被理解为“{{0}}}”
或“{0}\}”
。内部的{0}
是要用第一个参数替换的实际字段,外部的{/code>和}
符号是获取单个}
如果它还没有完成,它只分配给_name一次,因此它被认为是懒惰的,因为只有在第一次调用ToString()
时才会生成带花括号的字符串。你可以在这里按需阅读懒惰。@FrédéricHamidi哦,这有点狡猾hack@Mafii我知道“懒惰”这个词听起来有些贬义,但懒散的评估在任何方面都不是一种黑客行为。事实上,整个语言都是围绕着这种范式构建的。在这种情况下,NamedObject
的实现者使用封装来保证对象的行为符合预期,同时在某些情况下节省了一些性能。@KABoissonneault这绝不意味着贬义当然。我喜欢惰性评估有多神奇——但它让我更困惑的是,当它发生的时间和原因是什么,尤其是在这种情况下。它隐含着惰性,更像是一种解决方法。这是一段很好的代码,因为它是commindet:),所以字符串在if中的contidional为true之前不会被初始化,因为编译器不知道它是否会运行?(它欺骗了编译器?@Mafii将解释替换为“非惰性”备选方案。看起来他们想尽量减少创建NamedObject
实例的影响,以防没有人计划调用ToString
。哦,太酷了。很好的解释,很容易理解。我甚至没想过。他们这么做真是太糟糕了(考虑到只有一个字符串)无论如何,我看不出OP发布的代码有什么不同。如果他想运行它,他可以简单地运行它。
var value = "value";
String.Format(CultureInfo.InvariantCulture, "{{{0}}}", value); // will output {value}