比较
1
| String.Format("Hello {0}","World"); |
with
1
| "Hello {0}".Format("World"); |
为什么.Net设计人员为什么选择静态方法而不是实例方法?您怎么看?
Because the Format method has nothing to do with a string's current value.
对于所有字符串方法都是如此,因为.NET字符串是不可变的。
If it was non-static, you would need a string to begin with.
它确实是:格式字符串。
我相信这只是.NET平台中许多设计缺陷的另一个示例(我并不是说这是大火;我仍然发现.NET框架优于大多数其他框架)。
我实际上不知道答案,但我怀疑这与直接调用字符串文字的方法有关。
如果我没记错的话(因为我没有旧的IDE,所以我没有进行实际验证),早期版本的C#IDE很难在IntelliSense中检测到针对字符串文字的方法调用。关于API的可发现性。如果真是这样,键入以下内容不会给您任何帮助:
如果您被迫键入
1
| new String("{0}").Format(12); |
很明显,将Format方法设置为实例方法而不是静态方法没有任何好处。
.NET库是由提供给我们MFC的许多人设计的,特别是String类与MFC中的CString类非常相似。 MFC确实有一个实例Format方法(该方法使用printf样式格式代码而不是.NET的花括号样式),这很痛苦,因为没有CString文字之类的东西。因此,在我使用的MFC代码库中,我看到了很多这样的内容:
1 2
| CString csTemp ="";
csTemp.Format("Some string: %s", szFoo); |
这很痛苦。 (我并不是说上面的代码即使在MFC中也是执行操作的好方法,但这似乎是项目中大多数开发人员学习如何使用CString :: Format的方式)。基于这种传统,我可以想象到API设计人员正试图再次避免这种情况。
好吧,我想您必须对此非常讲究,但是就像人们所说的那样,由于隐含的语义,String.Format静态是更有意义的。考虑:
1 2 3 4 5 6 7 8
| "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. |
当我升级到VS2008和C#3时,我要做的第一件事就是做到这一点
1 2 3 4
| public static string F( this string format, params object[] args )
{
return String.Format(format, args);
} |
所以我现在可以从
更改我的代码
1
| String.Format("Hello {0}", Name); |
到
当时我更喜欢。
如今(2014年),我不再打扰,因为继续将它重新添加到我创建的每个随机项目中,或链接到一些实用程序库中,这是另一个麻烦。
.NET设计者为什么选择它?谁知道。看来完全是主观的。
我的钱都在
上
我找不到真正的其他正当理由
我认为这是因为Format本身并不是一个字符串,而是一个" format string"。大多数字符串等于" Bob Smith"或" 1010 Main St"之类的东西,或者等于您拥有的东西,而不等于" Hello {0}",通常,当您尝试使用模板创建另一个模板时,通常只将这些格式字符串放入其中字符串,就像工厂方法一样,因此将其自身借给静态方法。
我认为这是因为它是一个创建者方法(不确定是否有更好的名称)。它所做的就是获取您提供的内容并返回一个字符串对象。它不适用于现有对象。如果它是非静态的,则需要一个字符串开头。
.NET Strings are Immutable
Therefore having an instance method makes absolutely no sense.
通过这种逻辑,字符串类应该没有实例方法来返回该对象的修改后的副本,但是它具有很多实例(Trim,ToUpper等)。此外,框架中的许多其他对象也可以做到这一点。
我同意,如果要使其成为实例方法,则Format似乎是一个坏名字,但这并不意味着该功能不应该是实例方法。
为什么不呢?它与.NET Framework的其余部分一致
1
| "Hello {0}".ToString("Orion"); |
也许.NET设计者是这样做的,因为JAVA是这样做的...
拥抱并扩展。 :)
请参阅:http://discuss.techinterview.org/default.asp?joel.3.349728.40
因为Format方法与字符串的当前值无关。不使用字符串的值。它接受一个字符串并返回一个。
当您有一个保持某种状态的对象时,
实例方法是好的。格式化字符串的过程不会影响您正在操作的字符串(读取:不会修改其状态),它会创建一个新的字符串。
使用扩展方法,您现在也可以吃蛋糕也可以吃(即,如果可以帮助您晚上睡得更好,则可以使用后一种语法)。
我认为通常使用String.Format看起来更好,但是当您已经将字符串存储在要"格式化"的变量中时,我希望看到一个具有非静态功能的要点。
顺便说一句,字符串类的所有函数都不作用于字符串,而是返回一个新的字符串对象,因为字符串是不可变的。
C#的一个主要设计目标是使从C / C到C / C的过渡尽可能容易。对于仅具有C / C背景的人,在字符串文字上使用点语法看起来会很奇怪,并且格式化字符串是开发人员在使用该语言的第一天就可能会做的事情。因此,我相信他们可以使它变得更接近于熟悉的领域。
这是为了避免与.ToString()方法混淆。
例如:
1 2 3 4 5 6 7
| 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()是一种实用程序方法,可以将多个对象转换为格式化的字符串。
字符串的实例方法对该字符串有作用。
您当然可以:
1 2 3 4 5
| public static string FormatInsert( this string input, params object[] args) {
return string.Format( input, args );
}
"Hello {0}, I have {1} things.".FormatInsert("world", 3); |
String.Format的另一个原因是与C中的函数printf相似。它被认为可以使C开发人员更轻松地切换语言。
@Jared:
Non-overloaded, non-inherited static methods (like Class.b(a,c)) that take an instance as the first variable are semantically equivalent to a method call (like a.b(c))
不,不是。
(Assuming it compiles to the same CIL, which it should.)
那是你的错误。产生的CIL不同。区别在于不能在null值上调用成员方法,因此CIL插入对null值的检查。显然,这不是在静态变量中完成的。
但是,String.Format不允许使用null值,因此开发人员必须手动插入支票。从这个angular来看,成员方法的变体在技术上会更好。
我不知道他们为什么这么做,但这不再重要了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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);
}
} |
这很容易,恕我直言。
将实例作为第一个变量的非重载,非继承静态方法(如Class.b(a,c))在语义上等效于方法调用(如ab(c)),因此平台团队做了任意的美学选择。 (假定它应该编译为相同的CIL。)唯一知道的方法是问他们为什么。
可能他们这样做是为了使两个字符串在语法上彼此靠近,即
1
| String.Format("Foo {0}","Bar"); |
而不是
1
| "Foo {0}".Format("bar"); |
您想知道索引映射到什么;也许他们认为" .Format"部分只是在中间增加了噪音。
有趣的是,ToString方法(至少对于数字而言)是相反的:number.ToString(" 000"),格式字符串在右侧。
我还没有尝试过,但是您可以为您想要的扩展方法。我不会这样做,但是我认为它可以工作。
我还发现String.Format()与其他有图案的静态方法(例如Int32.Parse(),long.TryParse()等)更加一致。
如果要使用非静态格式,您也可以使用StringBuilder。
StringBuilder.AppendFormat()
我看不到它是静态的。.
静态方法的语义对我来说似乎更有意义。也许是因为它是原始的。在通常使用基元的地方,您希望使实用程序代码尽可能轻便地使用它们。此外,我认为String.Format的语义要比" MyString BLAH BLAH {0}"。Format更好。 ..
String.Format必须是静态方法,因为字符串是不可变的。将其设为实例方法将意味着您可以使用它来"格式化"或修改现有字符串的值。您无法做到这一点,而使其成为返回新字符串的实例方法将毫无意义。因此,这是一个静态方法。
String.Format至少接受一个String并返回另一个String。它不需要修改格式字符串即可返回另一个字符串,因此这样做没有任何意义(忽略其格式)。另一方面,使String.Format成为成员函数并不是一件容易的事,除非我不认为C#像C那样允许const成员函数。 [请纠正我,如果正确,请改此帖子。]
.NET字符串是不可变的
因此,使用实例方法绝对没有意义。
1 2 3 4 5
| 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. |