比較
String.Format("Hello {0}", "World");
と
"Hello {0}".Format("World");
.Net 設計者がインスタンス メソッドではなく静的メソッドを選択したのはなぜですか? どう思いますか?
Format メソッドは文字列の現在の値とは関係がないためです。
.NET 文字列は不変であるため、これはすべての文字列メソッドに当てはまります。
静的でない場合は、最初に文字列が必要になります。
フォーマット文字列。
これは、.NET プラットフォームの多くの設計上の欠陥の 1 つの例にすぎないと思います (これは炎上しているわけではありません。.NET フレームワークは、他のほとんどのフレームワークよりも優れていると思います)。
実際には答えはわかりませんが、文字列リテラルでメソッドを直接呼び出すという側面と関係があると思われます。
私の記憶が正しければ (私は古い IDE を手元に持っていないため、実際には検証しませんでした)、C# IDE の初期のバージョンでは、IntelliSense で文字列リテラルに対するメソッド呼び出しを検出するのに問題があり、発見しやすさに大きな影響を与えました。 APIの。その場合、次のように入力しても何の助けにもなりません。
"{0}".Format(12);
入力を強制された場合
new String("{0}").Format(12);
Format メソッドを静的メソッドではなくインスタンス メソッドにするメリットがないことは明らかです。
.NET ライブラリは、MFC を提供したのと同じ多くの人々によって設計されました。特に String クラスは、MFC の CString クラスに非常によく似ています。MFC にはインスタンスの Format メソッド (.NET の中かっこスタイルではなく、printf スタイルの書式設定コードを使用する) がありますが、CString リテラルのようなものがないため、これは面倒です。したがって、私が取り組んだ MFC コードベースには、次のようなものがたくさんあります。
CString csTemp = "";
csTemp.Format("Some string: %s", szFoo);
これは痛いです。(上記のコードが MFC でも優れた方法であると言っているわけではありませんが、プロジェクトのほとんどの開発者が CString::Format の使用方法を学んだ方法のようです)。その遺産から、API 設計者はそのような状況を再び回避しようとしていたことが想像できます。
まあ、あなたはそれについてかなりこだわる必要があると思いますが、人々が言っているように、暗黙のセマンティクスのために 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.
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 設計者がそれを選んだ理由は? 知るか。完全に主観的なようです。私のお金はどちらかにある
私が見つけることができる他の正当な理由は実際にはありません
Format は文字列自体ではなく、「フォーマット文字列」を取るためだと思います。ほとんどの文字列は、"Bob Smith" や "1010 Main St" などに相当し、"Hello {0}" には相当しません。通常、テンプレートを使用して別のテンプレートを作成する場合にのみ、これらの書式文字列を入力します。ファクトリ メソッドのような文字列であるため、静的メソッドに適しています。
クリエーターメソッドだからだと思います(もっといい名前があるかどうかはわかりません)。与えられたものを受け取り、単一の文字列オブジェクトを返すだけです。既存のオブジェクトには作用しません。静的でない場合は、最初に文字列が必要になります。
JAVAがこのようにしたので、.NET設計者がこのようにしたのかもしれません...
抱きしめて伸ばす。:)
参照: http://discuss.techinterview.org/default.asp?joel.3.349728.40
.NET 文字列は不変
であるため、インスタンス メソッドを使用してもまったく意味がありません。
そのロジックにより、文字列クラスには、オブジェクトの変更されたコピーを返すインスタンス メソッドが存在しないはずですが、十分に存在します(Trim、ToUpper など)。さらに、フレームワーク内の他の多くのオブジェクトもこれを行います。
彼らがそれをインスタンスメソッドにするとしたら、それは悪い名前のように思えることに同意しますが、Format
それは機能がインスタンスメソッドであってはならないという意味ではありません.
なぜこれではないのですか?.NET フレームワークの残りの部分と 一貫性があります。
"Hello {0}".ToString("Orion");
Format メソッドは文字列の現在の値とは関係がないためです。文字列の値は使用されません。文字列を受け取り、それを返します。
A big design goal for C# was to make the transition from C/C++ to it as easy as possible. Using dot syntax on a string literal would look very strange to someone with only a C/C++ background, and formatting strings is something a developer will likely do on day one with the language. So I believe they made it static to make it closer to familiar territory.
.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);
もう 1 つの理由String.Format
は、C からの機能との類似性ですprintf
。これにより、C 開発者が言語を簡単に切り替えられるようになるはずでした。
@ジャレッド:
インスタンスを最初の変数として受け取る、オーバーロードも継承もされていない静的メソッド (Class.b(a,c) など) は、メソッド呼び出し (ab(c) など) と意味的に同等です。
いいえ、そうではありません。
(それが同じ CIL にコンパイルされると仮定すると、そうあるべきです。)
それはあなたの間違いです。生成される CIL は異なります。違いは、値に対してメンバー メソッドを呼び出すことができないnull
ため、CIL が値に対してチェックを挿入するnull
ことです。これは明らかに静的バリアントでは行われません。
ただし、値を許可String.Format
しないため、開発者は手動でチェックを挿入する必要がありました。この観点から、メンバーメソッドのバリアントは技術的に優れています。null
インスタンス メソッドは、何らかの状態を維持するオブジェクトがある場合に適しています。文字列をフォーマットするプロセスは、操作している文字列に影響を与えず (読み取り: その状態を変更しません)、新しい文字列を作成します。
拡張メソッドを使用すると、ケーキを手に入れて食べることもできます (つまり、後者の構文が夜の睡眠を改善するのに役立つ場合は、後者の構文を使用できます)。
一般的には String.Format を使用する方が見栄えが良いと思いますが、「フォーマット」したい変数に文字列が既に格納されている場合は、非静的関数が必要な点がわかりました。
余談ですが、文字列クラスのすべての関数は文字列に作用しませんが、文字列は不変であるため、新しい文字列オブジェクトを返します。
なぜ彼らがそれをしたのかはわかりませんが、それはもはや問題ではありません:
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);
}
}
それはずっと簡単に流れます、IMHO。
静的であることには何の問題もありません..
静的メソッドのセマンティクスは、私にはもっと理にかなっているようです。プリミティブだからなのかな。プリミティブが頻繁に使用される場所では、それらを操作するためのユーティリティ コードをできるだけ軽量にしたいと考えています。 ..
まだ試していませんが、必要な拡張メソッドを作成できます。私はそれをしませんが、うまくいくと思います。
また、、 などString.Format()
の他のパターン化された静的メソッドと一致していることもわかりました。Int32.Parse()
long.TryParse()
StringBuilder
非静的フォーマットが必要な場合
は、クラウドも使用します。StringBuilder.AppendFormat()
インスタンスを最初の変数として受け取る、オーバーロードされておらず、継承されていない静的メソッド (Class.b(a,c) など) は、メソッド呼び出し (ab(c) など) と意味的に同等であるため、プラットフォーム チームは任意の、審美的な選択。(それが同じ CIL にコンパイルされると仮定すると、そうあるべきです。) 知る唯一の方法は、理由を尋ねることです。
おそらく彼らは、2 つの文字列を辞書的に近づけるためにそれを行ったのでしょう。
String.Format("Foo {0}", "Bar");
それ以外の
"Foo {0}".Format("bar");
インデックスが何にマップされているかを知りたい。おそらく彼らは、「.Format」部分が途中でノイズを追加するだけだと考えていました。
興味深いことに、ToString メソッド (少なくとも数値の場合) は反対です: number.ToString("000") の右側にフォーマット文字列があります。
文字列は不変であるため、String.Format は静的メソッドである必要があります。インスタンスメソッドにするということは、それを使用して既存の文字列の値を「フォーマット」または変更できることを意味します。これはできません。新しい文字列を返すインスタンス メソッドにするのは意味がありません。したがって、これは静的メソッドです。
String.Format
少なくとも 1 つの文字列を取り、別の文字列を返します。別の文字列を返すためにフォーマット文字列を変更する必要はないため、それを行う意味はほとんどありません (フォーマットを無視します)。一方で、String.Format
C# では C++ のように const メンバー関数を使用できるとは思えないことを除けば、メンバー関数にするのはそれほど難しいことではありません。[もしそうなら、私とこの投稿を修正してください。]
.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.