为什么 String.Format 是静态的?[关闭]

Why is String.Format static? [closed]

提问人:Jakub Šturc 提问时间:8/23/2008 最后编辑:Orion EdwardsJakub Šturc 更新时间:4/8/2015 访问量:5891

问:


想改进这个问题吗?更新问题,以便可以通过编辑这篇文章用事实和引文来回答。

4年前关闭。

比较

String.Format("Hello {0}", "World");

"Hello {0}".Format("World");

为什么 .Net 设计人员选择静态方法而不是实例方法?你觉得怎么样?

.net 字符串

评论


答:

5赞 Thomas Owens 8/23/2008 #1

我认为这是因为它是一种创建者方法(不确定是否有更好的名字)。它所做的只是接受你给它的东西并返回一个字符串对象。它不对现有对象进行操作。如果它是非静态的,则需要一个字符串作为开头。

3赞 Ryan Farley 8/23/2008 #2

因为 Format 方法与字符串的当前值无关。不使用字符串的值。它接受一个字符串并返回一个。

1赞 Rob Cooper 8/23/2008 #3

我认为它是静态的没有错。

静态方法的语义对我来说似乎更有意义。也许是因为它是原始的。在经常使用基元的地方,您希望使使用它们的实用程序代码尽可能轻。此外,我认为 String.Format 的语义比“MyString BLAH BLAH {0}”要好得多。格式 ...

评论

0赞 ehdv 5/3/2012
它是静态的并没有错;我对此感到疑惑的原因是,与 相比,它增加了长度,并且使将字符串文字转换为格式化字符串变得复杂。不是很多,但足够了,实例方法会很有用。"my {0} string".Format(args)
2赞 Jason Bunting 8/23/2008 #4

当您有一个维护某种状态的对象时,实例方法很好;格式化字符串的过程不会影响您正在操作的字符串(阅读:不修改其状态),它会创建一个新字符串。

使用扩展方法,您现在可以吃蛋糕并吃掉它(即,如果后一种语法可以帮助您在晚上睡得更好,则可以使用后者语法)。

1赞 Dan Blair 8/23/2008 #5

我还没有尝试过,但你可以为你想要的东西制作一个扩展方法。我不会这样做,但我认为它会起作用。

此外,我发现更符合其他模式化静态方法,如 、 等。String.Format()Int32.Parse()long.TryParse()

如果你想要一个非静态格式,你也可以使用一个。StringBuilder.AppendFormat()StringBuilder

-1赞 Mat Noguchi 8/23/2008 #6

String.Format至少接受一个 String 并返回另一个 String。它不需要修改格式字符串即可返回另一个字符串,因此这样做意义不大(忽略它的格式)。另一方面,成为成员函数不会有太大的延伸,除了我认为 C# 不允许像 C++ 那样的常量成员函数。[如果是这样,请纠正我和这篇文章。String.Format

2赞 Kibbee 8/23/2008 #7

我认为使用 String.Format 通常看起来更好,但是当您已经将字符串存储在要“格式化”的变量中时,我可以看到想要拥有非静态函数的意义。

顺便说一句,string 类的所有函数都不会作用于字符串,而是返回一个新的字符串对象,因为字符串是不可变的。

评论

0赞 Alex Lowe 7/29/2020
但是,当其他方法(如和不是)是静态的时,这是不一致的。String.FormatTrimPadLeft
50赞 Konrad Rudolph 8/23/2008 #8

因为 Format 方法与字符串的当前值无关。

这适用于所有字符串方法,因为 .NET 字符串是不可变的。

如果它是非静态的,则需要一个字符串作为开头。

它确实是:格式字符串。

我相信这只是 .NET 平台中许多设计缺陷的另一个例子(我并不是说这是火焰;我仍然发现 .NET 框架优于大多数其他框架)。

评论

2赞 Tim 12/24/2008
为什么不是;这是公认的答案吗?
1赞 Jakub Šturc 6/28/2009
@tim:因为我认为安德鲁斯的回答更好。:-)
4赞 Konrad Rudolph 6/28/2009
实际上,我也更喜欢公认的答案,因为它完美地回答了这个问题。我自己的回答更像是对静态函数设计的一些假设的评论。
1赞 Humphrey Bogart 2/24/2010
反射为“不可变”赋予了一个新的同义词:可变的......:P
-1赞 user2189331 8/23/2008 #9

String.Format 必须是静态方法,因为字符串是不可变的。使其成为实例方法意味着您可以使用它来“格式化”或修改现有字符串的值。这是你做不到的,让它成为一个返回新字符串的实例方法将没有意义。因此,它是一种静态方法。

评论

9赞 Greg 2/18/2010
格式与替换或子字符串有何不同?不会更改实际字符串,返回新字符串。格式本来可以效仿。
0赞 2/24/2010
没错,但可以这样想:如果 Format 是一个实例方法,你必须声明你的字符串,然后对其调用 Format。这始终是一个两步过程。例如。1) 字符串 strTemp;2) strTemp.Format(“{0}”, “Hello World”);更清洁,使其静态。
0赞 2/24/2010
从语义上讲,Replace 和 Substring 作为实例方法很有意义。格式本来可以采用任何一种方式,但如果它是静态的,则使用会更干净。
9赞 Fredrik Kalseth 8/23/2008 #10

好吧,我想你必须对它相当讲究,但就像人们所说的那样,由于隐含的语义,String.Format 是静态的更有意义。考虑:

"Hello {0}".Format("World"); // this makes it sound like Format *modifies* 
                             // the string, which is not possible as 
                             // strings are immutable.

string[] parts = "Hello World".Split(' ');    // this however sounds right, 
                                             // because it implies that you 
                                             // split an existing string into 
                                             // two *new* strings.

评论

8赞 davidtbernal 3/20/2011
你的第二个例子真的崩溃了,比如,IMO。"a b c".Replace("a", "kitty")
4赞 jm. 8/23/2008 #11

也许 .NET 设计者这样做是因为 JAVA 这样做的......

拥抱和延伸。:)

请参见:http://discuss.techinterview.org/default.asp?joel.3.349728.40

评论

0赞 Joachim Sauer 3/9/2009
AFAIK .NET 方法比 Java 方法更旧(Java 仅在版本 5 中获取它)。
0赞 jm. 3/21/2009
哼?Java 1.5:java.sun.com/j2se/1.5.0/docs/api/java/lang/...
0赞 Simon Nickerson 10/1/2009
@jm:出于 Sun 最熟悉的奇怪的营销原因,Java 1.5 和 Java 5 是一回事。
8赞 Orion Edwards 8/23/2008 #12

当我升级到 VS2008 和 C#3 时,我做的第一件事就是这样做

public static string F( this string format, params object[] args )
{
    return String.Format(format, args);
}

所以我现在可以将我的代码从

String.Format("Hello {0}", Name);

"Hello {0}".F(Name);

这是我当时更喜欢的。 如今(2014 年),我不再打扰,因为不断将其重新添加到我创建的每个随机项目中,或链接到某个 Bag-of-utils 库中只是另一个麻烦。

至于为什么.NET设计人员选择它?谁知道呢。这似乎完全是主观的。 我的钱在任一

  • 复制 Java
  • 当时写它的人主观上更喜欢它。

我真的找不到任何其他正当理由

评论

2赞 Jakub Šturc 6/28/2009
我不认为扩展方法是正确的方法。我为读者创造了wft时刻。我相信在 c# 中我们被困在静态版本中。
1赞 Arnis Lapsa 2/24/2010
这是主观的,@Jakub。对我来说 - 当我看到卷曲的牙套时,我立即知道什么是正确的。
2赞 Ken 2/24/2010
我不确定什么是“wft moment”,但这与任何其他扩展方法的使用有何不同?
1赞 Kugel 7/15/2010
我这样做并将其放在 String 所在的 System 命名空间下。
-2赞 FlySwat 8/23/2008 #13

.NET 字符串是不可变的

因此,拥有实例方法完全没有意义。

String foo = new String();

foo.Format("test {0}",1); // Makes it look like foo should be modified by the Format method. 

string newFoo = String.Format(foo, 1); // Indicates that a new string will be returned, and foo will be unaltered.

评论

0赞 Alex Lowe 7/29/2020
但是,这与其他作为实例方法并返回新字符串的操作不一致。InsertNormalizePadLeft 等都完全按照描述工作。如果是静态的,因为字符串是不可变的,那么所有这些也应该是静态的,但事实并非如此。StringFormat
1赞 Jared Updike 8/23/2008 #14

将实例作为第一个变量的非重载、非继承的静态方法(如 Class.b(a,c))在语义上等同于方法调用(如 a.b(c)),因此平台团队做出了任意的、审美的选择。(假设它编译为相同的 CIL,它应该编译。唯一知道的方法就是问他们为什么。

他们这样做可能是为了让两个字符串在词典上彼此靠近,即

String.Format("Foo {0}", "Bar");

而不是

"Foo {0}".Format("bar");

您想知道索引映射到什么;也许他们认为“.格式“部分只是在中间增加了噪音。

有趣的是,ToString 方法(至少对于数字而言)正好相反:number。ToString(“000”) 格式字符串位于右侧。

4赞 Orion Edwards 8/23/2008 #15

.NET 字符串是不可变的
因此,拥有实例方法完全没有意义。

按照这个逻辑,字符串类不应该有返回对象的修改副本的实例方法,但它有很多(Trim、ToUpper 等)。此外,框架中的许多其他对象也这样做。

我同意,如果他们要使其成为实例方法,这似乎是一个不好的名字,但这并不意味着该功能不应该是实例方法。Format

为什么不这样呢?它与 .NET Framework 的其余部分一致

"Hello {0}".ToString("Orion");
2赞 Konrad Rudolph 8/23/2008 #16

@Jared:

将实例作为第一个变量的非重载、非继承的静态方法(如 Class.b(a,c))在语义上等同于方法调用(如 a.b(c))

不,他们不是。

(假设它编译为相同的 CIL,它应该编译。

那是你的错误。产生的CIL是不同的。区别在于不能对值调用成员方法,因此 CIL 会插入针对值的检查。这显然不是在静态变体中完成的。nullnull

但是,不允许值,因此开发人员必须手动插入检查。从这个角度来看,成员方法变体在技术上会更胜一筹。String.Formatnull

评论

2赞 Jared Updike 1/28/2009
我认为当有人(Python)告诉我将成员函数视为静态函数时,我认为这是一个非常有用的范式,并将显式的“this”对象作为第一个元素。感谢您对零点的深思熟虑!顺便说一句,重载为静态/成员方法等价性增加了更多复杂性。
30赞 Andrew 8/23/2008 #17

我实际上不知道答案,但我怀疑这与直接在字符串文字上调用方法有关。

如果我没记错的话(我实际上没有验证这一点,因为我手边没有旧的 IDE),早期版本的 C# IDE 在检测 IntelliSense 中针对字符串文本的方法调用时遇到了问题,这对 API 的可发现性有很大影响。如果是这种情况,键入以下内容不会为您提供任何帮助:

"{0}".Format(12);

如果您被迫输入

new String("{0}").Format(12);

很明显,将 Format 方法作为实例方法而不是静态方法没有任何优势。

.NET 库是由许多为我们提供 MFC 的人设计的,特别是 String 类与 MFC 中的 CString 类非常相似。MFC 确实有一个实例 Format 方法(它使用 printf 样式的格式设置代码,而不是 .NET 的大括号样式),这很痛苦,因为没有 CString 文本这样的东西。因此,在我工作的 MFC 代码库中,我看到了很多这样的内容:

CString csTemp = "";
csTemp.Format("Some string: %s", szFoo);

这很痛苦。(我并不是说上面的代码是即使在 MFC 中也能做事的好方法,但这似乎是项目中大多数开发人员学习如何使用 CString::Format 的方式)。从这个传统来看,我可以想象 API 设计者正试图再次避免这种情况。

评论

8赞 Humphrey Bogart 2/24/2010
...所以由于IDE设计无能,它是这样设计的?
1赞 chtenb 1/13/2016
那么,既然 IDE 更好了,他们为什么不稍后添加表单呢?据我所知,它不会破坏任何东西。"".Format
2赞 Keith 8/23/2008 #18

这是为了避免与方法混淆。.ToString()

例如:

double test = 1.54d;

//string.Format pattern
string.Format("This is a test: {0:F1}", test );

//ToString pattern
"This is a test: " + test.ToString("F1");

如果 Format 是字符串上的实例方法,则可能会导致混淆,因为模式不同。

String.Format() 是一种将多个对象转换为格式化字符串的实用方法。

字符串上的实例方法对该字符串执行某些操作。

当然,您可以:

public static string FormatInsert( this string input, params object[] args) {
    return string.Format( input, args );
}

"Hello {0}, I have {1} things.".FormatInsert( "world", 3);
2赞 nollidge 8/26/2008 #19

我不知道他们为什么要这样做,但这已经不重要了:

public static class StringExtension
{
    public static string FormatWith(this string format, params object[] args)
    {
        return String.Format(format, args);
    }
}

public class SomeClass
{
    public string SomeMethod(string name)
    {
        return "Hello, {0}".FormatWith(name);
    }
}

恕我直言,这要容易得多。

2赞 Kociub 9/2/2008 #20

另一个原因是与 C 函数的相似性。它应该让 C 开发人员更容易切换语言。String.Formatprintf

2赞 munificent 9/16/2008 #21

C# 的一大设计目标是尽可能轻松地从 C/C++ 过渡到 C/C++。对于只有 C/C++ 背景的人来说,在字符串文字上使用点语法看起来非常奇怪,而格式化字符串是开发人员在使用该语言的第一天可能会做的事情。所以我相信他们让它静止,让它更接近熟悉的领域。

6赞 Hj David Kearns 9/16/2008 #22

我认为这是因为 Format 本身不采用字符串,而是采用“格式字符串”。大多数字符串都等同于“Bob Smith”或“1010 Main St”之类的东西,而不是“Hello {0}”,通常只有在尝试使用模板创建另一个字符串(如工厂方法)时才放入这些格式字符串,因此它本身就适合静态方法。

评论

0赞 Thomas Ahle 4/6/2014
这似乎是迄今为止最好的答案。但是,如果它应该“与字符串不同”,那么为什么要把它放在 String 类中......