39

比较

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

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

为什么.Net 设计者选择静态方法而不是实例方法?你怎么看?

4

22 回答 22

49

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

对于所有字符串方法都是如此,因为 .NET 字符串是不可变的。

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

它确实:格式字符串。

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

于 2008-08-22T19:22:33.320 回答
29

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

如果我没记错的话(我实际上并没有验证这一点,因为我手边没有旧的 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 设计者正试图再次避免这种情况。

于 2008-08-23T11:05:01.653 回答
9

好吧,我想您必须对此非常挑剔,但是就像人们所说的那样,由于隐含的语义,因此 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.
于 2008-08-22T20:38:40.767 回答
8

当我升级到 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 年)我不打扰,因为将它重新添加到我创建的每个随机项目或链接到一些实用程序库中只是另一个麻烦。

至于 .NET 设计者为何选择它?谁知道。这似乎完全是主观的。我的钱都在

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

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

于 2008-08-23T04:27:03.323 回答
6

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

于 2008-09-16T10:28:21.197 回答
5

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

于 2008-08-22T19:17:18.920 回答
4

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

拥抱和扩展。:)

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

于 2008-08-23T00:38:38.647 回答
4

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

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

我同意,如果他们将其设为实例方法,Format这似乎是个坏名字,但这并不意味着该功能不应该是实例方法。

为什么不是这个?它与.NET 框架的其余部分 一致

"Hello {0}".ToString("Orion");
于 2008-08-23T06:44:52.760 回答
3

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

于 2008-08-22T19:17:26.530 回答
2

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

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

于 2008-08-22T19:19:32.330 回答
2

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

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

于 2008-08-22T19:22:32.103 回答
2

@贾里德:

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

不,他们不是。

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

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

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

于 2008-08-23T08:25:19.257 回答
2

这是为了避免与.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);
于 2008-08-23T11:10:27.987 回答
2

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

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);
    }
}

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

于 2008-08-25T22:15:14.160 回答
2

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

于 2008-09-02T12:34:17.817 回答
2

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

于 2008-09-16T02:44:53.977 回答
1

我认为它是静态的没有任何问题..

静态方法的语义对我来说似乎更有意义。也许是因为它是原始的。在经常使用原语的地方,您希望使使用它们的实用程序代码尽可能轻巧。另外,我认为String.Format的语义优于"MyString BLAH BLAH {0}".Format。 ..

于 2008-08-22T19:19:10.443 回答
1

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

此外,我发现String.Format()更符合其他带图案的静态方法,如Int32.Parse(),long.TryParse()等。

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

于 2008-08-22T19:21:06.803 回答
1

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

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

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

代替

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

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

有趣的是,ToString 方法(至少对于数字)是相反的:number.ToString("000") 右侧的格式字符串。

于 2008-08-23T05:41:40.930 回答
-1

String.Format至少接受一个字符串并返回一个不同的字符串。它不需要修改格式字符串来返回另一个字符串,所以这样做没有什么意义(忽略它的格式)。另一方面,成为String.Format成员函数不会有太大的难度,除非我认为 C# 不允许像 C++ 那样的 const 成员函数。[如果是,请纠正我和这篇文章。]

于 2008-08-22T19:22:23.663 回答
-1

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

于 2008-08-22T20:02:37.220 回答
-2

.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.
于 2008-08-23T05:20:58.437 回答