web-dev-qa-db-ja.com

なぜ/いつToStringをオーバーライドするのが適切ですか?

私はC#を勉強していますが、次の例に示すように、ToStringをオーバーライドすることのポイントと利点は何かと思います。

これは、オーバーライドなしの一般的な方法を使用して、より簡単な方法で実行できますか?

public string GetToStringItemsHeadings
{
    get { return string.Format("{0,-20} {1, -20}", "Office Email", "Private Email"); }
}


public override string ToString()
{
    string strOut = string.Format("{0,-20} {1, -20}", m_work, m_personal);
    return strOut;
}
102
3D-kreativ
  • ToStringをオーバーライドする必要がありますか? いいえ

  • 別の方法でオブジェクトの文字列表現を取得できますか? はい

ただし、ToStringを使用することで、すべてのオブジェクトに共通のメソッドを使用しているため、他のクラスはこのメソッドについて知っています。たとえば、.NETフレームワークがオブジェクトを文字列表現に変換したいときはいつでも、ToStringが最有力候補です(より複雑なフォーマットオプションを提供したい場合は、他にもあります)。

具体的には、

_Console.WriteLine(yourObject);
_

yourObject.ToString()を呼び出します。

127
Konrad Rudolph

.NET開発シリーズの Framework Design Guidelines から直接答えを提供します。

[〜#〜] avoid [〜#〜]ToStringから例外をスローする

[〜#〜] consider [〜#〜]インスタンスに関連付けられた一意の文字列を返します。

[〜#〜] consider [〜#〜]ToStringの出力をこのタイプの解析メソッドの有効な入力にする。

[〜#〜] do [〜#〜]ToStringに目に見える副作用がないことを確認します。

[〜#〜] do [〜#〜]適切な許可を要求した後にのみ、ToStringのオーバーライドを通じてセキュリティ上重要な情報を報告する。アクセス許可の要求が失敗した場合、セキュリティ上重要な情報を除く文字列を返します。

_Object.ToString_メソッドは、一般的な表示およびデバッグの目的で使用することを目的としています。デフォルトの実装では、オブジェクトタイプ名が提供されます。デフォルトの実装はあまり有用ではないため、メソッドをオーバーライドすることをお勧めします。

[〜#〜] do [〜#〜]興味深い人間が読める文字列が返される場合は常にToStringをオーバーライドします。デフォルトの実装はあまり有用ではなく、カスタム実装はほとんど常により多くの価値を提供できます。

[〜#〜] do [〜#〜]一意ではあるが読み取り不可能なIDよりもわかりやすい名前を使用します。

また、Chris SellがガイドラインでToStringはユーザーインターフェイスにとって危険であることが多いと説明しているため、言及する価値もあります。一般的に、私の経験則では、UIに情報をバインドするために使用されるプロパティを公開し、開発者に診断情報を表示するためにToStringオーバーライドを残します。 DebuggerDisplayAttributeで型を修飾することもできます。

[〜#〜] do [〜#〜]ToStringから返される文字列を短くするようにします。デバッガーはToStringを使用して、開発者に表示されるオブジェクトのテキスト表現を取得します。デバッガーが表示できる長さよりも文字列が長い場合、デバッグエクスペリエンスが妨げられます。

[〜#〜] do [〜#〜]カルチャ依存情報を返すときの現在のスレッドカルチャに基づく文字列の書式設定。

[〜#〜] do [〜#〜]オーバーロードToString(string format)を提供するか、IFormattableを実装します。 ToStringから返される文字列はカルチャに依存するか、文字列をフォーマットするさまざまな方法があります。たとえば、DateTimeはオーバーロードを提供し、IFormattableを実装します。

DO NOTは、ToStringから空の文字列またはnullを返します

私はこれらのガイドラインを誓いますが、そうすべきです。 ToStringのこの1つのガイドラインだけでは、私のコードがどのように改善されたかを説明することはできません。 IEquatable(Of T)IComparable(Of T)のようなものにも同じことが言えます。これらのことにより、コードは非常に機能的になり、後から時間をかけて実装することを後悔することはありません。

個人的に、ユーザーインターフェイスにToStringmuchを実際に使用したことはありません。何らかのプロパティまたはメソッドを常に公開しています。ほとんどの場合、ToStringをデバッグおよび開発者の目的に使用する必要があります。重要な診断情報を表示するために使用します。

129
David Anderson

ToString()をオーバーライドすると、クラスの人間が読める便利な文字列表現を提供できます。

これは、出力がクラスに関する有用な情報を明らかにできることを意味します。たとえば、Personクラスがある場合は、ToString()に個人のID、名、姓などを出力させることを選択できます。これは、デバッグまたはログを記録するときに非常に役立ちます。

あなたの例に関しては-このクラスが何であるかを知らずにオーバーライドが有用かどうかを見分けるのは困難ですが、実装自体は問題ありません。

39
Rob Levine

常に適切ですが、表示するものの背後にある意図を慎重に検討してください

より良い質問は尋ねることです:

なぜToString()をオーバーライドするのですか?

ToString()は、オブジェクトの状態へのウィンドウです。要件としてstateを重視。 Java/C#のような強力なOOP言語は、すべてをクラスにカプセル化することでOOPモデルを乱用します。強力なOOPモデルに従わない言語でコーディングしていると想像してください。クラスと関数のどちらを使用するかを検討してください。関数(動詞、アクションなど)として使用し、内部状態が入出力間で一時的にのみ維持される場合、ToString()は値を追加しません。

他の人が言及したように、ToString()で出力するwhatを考慮することが重要です。これは、デバッガまたは他のシステムで使用できるためです。

ToStringメソッドをオブジェクトの--helpパラメーターとして想像するのが好きです。短く、読みやすく、明白で、表示しやすいものでなければなりません。オブジェクトが何であるかを表示する必要がありますisではなく、オブジェクトを表示しますdoes。すべてを念頭に置いて検討しましょう...

ユースケース-TCPパケットの解析:

アプリケーションレベルのみのネットワークキャプチャではなく、pcapキャプチャのようなより肉付きのあるものです。

TCPレイヤーのみのToString()をオーバーロードして、コンソールにデータを印刷できるようにします。それには何が含まれますか?クレイジーになり、すべてのTCP詳細を解析できます(つまり、TCPは複雑です)...

含まれるもの:

  • 送信元ポート
  • 宛先ポート
  • シーケンス番号
  • 謝辞番号
  • データオフセット
  • ウィンドウオフセット
  • チェックサム
  • 緊急ポインタ
  • オプション(私はevenではありません)

しかし、100個のパケットでTCP.ToString()を呼び出している場合、すべてのジャンクを受信したいでしょうか?もちろんそうではありませんが、それは情報過多になります。簡単で明白な選択も最も賢明です...

人々が期待するものを公開します:

  • 送信元ポート
  • 宛先ポート

私は人間が解析するのは簡単ですが、 [〜#〜] ymmv [〜#〜] の賢明な出力を好みます。

TCP:[destination:000, source:000]

複雑なことは何もありません。出力は解析するマシン用ではありません(つまり、人々がコードを乱用していない限り)。意図した目的は人間が読みやすいようにすることです。

しかし、私が前に話したそのジューシーな情報の残りすべてについてはどうでしょうか?それに着きますが、最初に...


ToString()これまでで最も価値があり、十分に活用されていないメソッドの1つ

次の2つの理由から:

  1. 人々はToString()が何のためにあるのか理解していない
  2. 基本 'Object'クラスには、同様に重要な別の文字列メソッドがありません。

理由1-ToString()の有用性を乱用しないでください:

多くの人がToString()を使用して、オブジェクトの単純な文字列表現を引き出します。 C#マニュアルにも次のように記載されています。

ToStringは、.NET Frameworkの主要な書式設定方法です。オブジェクトを文字列表現に変換して、表示に適したものにします。

Display、さらに処理しません。それは、上記のTCPパケットのニース文字列表現を取得し、正規表現:: cringe ::を使用してソースポートをプルするという意味ではありません。

rightの方法は、SourcePortプロパティでToString()を直接呼び出します(BTWはushortなので、ToString()は既に使用可能になっているはずです) 。

マシン解析のために複雑なオブジェクトの状態をパッケージ化するために、より堅牢なものが必要な場合は、構造化されたシリアル化戦略を使用することをお勧めします。

幸いなことに、そのような戦略は非常に一般的です:

  • ISerializable(C#)
  • ピクルス(Python)
  • JSON(Javascriptまたはそれを実装する任意の言語)
  • SOAP
  • 等...

注:PHPを使用している場合を除き、herp-derpには、そのための関数があります:: snicker ::

理由2-ToString()では不十分です:

コアでこれを実装する言語はまだ見ていませんが、このアプローチのバリエーションを実際に見て使用しています。

そのうちのいくつかが含まれます:

  • ToVerboseString()
  • ToString(verbose = true)

基本的に、TCPパケットの状態の毛むくじゃらの混乱shouldは、人間が読みやすいように記述されています。 TCPについて話している「死んだ馬をたたく」ことを避けるために、ToString()とToVerboseString()が十分に活用されていないと思う#1の場合に「指を向けます」...

ユースケース-配列:

主に1つの言語を使用する場合、おそらくその言語のアプローチに慣れているでしょう。私のように異なる言語間を飛び回る人にとっては、さまざまなアプローチがいらいらすることがあります。

つまり、これが私を苛立たせた回数は、すべてのヒンドゥー教の神のすべての指を合わせた合計よりも大きい。

さまざまな 言語が一般的に使用する場合があります hacks および few that get it right =。車輪の再発明が必要なものもあれば、浅いダンプを行うものもあれば、深いダンプを行うものもありますが、どれも私が望むような動作をしません...

私が求めているのは非常に簡単なアプローチです:

print(array.ToString());

出力: 'Array [x]'または 'Array [x] [y]'

ここで、xは最初の次元のアイテム数、yは2番目の次元のアイテム数、または2番目の次元がギザギザであることを示す値です(最小/最大範囲?)。

そして:

print(array.ToVerboseString());

私はきれいなものに感謝しているので、全体をきれいに印刷して出力します。

うまくいけば、これは長い間私を悩ませていたトピックにいくらかの光を当てます。少なくとも、私はPHPersがこの答えに賛成票を投じるためにちょっとしたトロールベイトを振りかけました。

13
Evan Plaice

本当に、それは何よりも優れた実践です。

ToString()は、一般に人間が消費するために、オブジェクトの文字列表現を返すために多くの場所で使用されます。多くの場合、同じ文字列を使用してオブジェクトをリハイドレートできます(たとえば、intまたはDateTimeを考えてください)が、それは常に与えられるわけではありません(たとえば、ツリーには、単に表示する便利な文字列表現がある場合があります)カウントですが、それを使用して再構築することはできません)。

特に、デバッガーはこれを使用して、ウォッチウィンドウ、イミディエイトウィンドウなどに変数を表示します。したがって、ToStringは実際にデバッグに非常に役立ちます。

また、一般に、そのような型には、多くの場合、文字列を返す明示的なメンバーも含まれます。たとえば、Lat/Longペアには、たとえば_"-10, 50"_を返すToDecimalDegreesがありますが、Lat/Longペアの別の形式であるため、ToDegreesMinutesSecondsもあります。その同じタイプは、デバッグのようなもの、またはWebページのレンダリングのようなもの(たとえば、Razor書き込みの_@_コンストラクト)の 'デフォルト'を提供するものの1つでToStringもオーバーライドする出力ストリームへの非文字列式のToString()結果。

9
Andras Zoltan

最も有用な情報はすでに提供されていると思いますが、2セントを追加します。

  • ToString()はオーバーライドされることを意図しています。デフォルトの実装は型名を返します。この型名は、(特に多くのオブジェクトを扱う場合に)役に立つ場合がありますが、ほとんどの場合は十分ではありません。

  • デバッグのために、DebuggerDisplayAttributeを使用できることに注意してください。詳細については、こちらをご覧ください こちら

  • 原則として、POCOでは、常にToString()をオーバーライドできます。 POCOはデータの構造化された表現であり、通常は文字列になります。

  • オブジェクトのテキスト表現になるようにToStringを設計します。主なフィールドとデータ、コレクションに含まれるアイテムの数などの説明かもしれません。

  • 常にその文字列を1行に収め、重要な情報のみを取得するようにしてください。 Name、Address、Numberなどのプロパティを持つPersonクラスがある場合、メインデータのみを返します(ID番号に名前を付けます)。

  • ToString()の適切な実装をオーバーライドしないように注意してください。一部のフレームワーククラスは既にToString()を実装しています。デフォルトの実装をオーバーライドするのは悪いことです。人々はToString()から特定の結果を期待し、別の結果を得るでしょう。

ToString()の使用を恐れないでください。私が注意する唯一のことは、機密情報を返すことです。それ以外は、リスクは最小限です。確かに、一部の人が指摘しているように、他のクラスは情報にアクセスするたびにToStringを使用します。しかし、実際の情報を取得するよりも、型名を返す方が良いと見なされるのはいつですか?

6
Bruno Brant

object.ToString()は、オブジェクトを文字列表現に変換します。ユーザーが作成したクラスでToString()を呼び出したときに返される内容を変更する場合は、そのクラスでToString()をオーバーライドする必要があります。

6
Robbie

ToStringをオーバーライドしない場合は、Objectがクラスの短い型名である基本クラスの実装を取得します。

ToStringの他の、より意味のある、または便利な実装が必要な場合は、オーバーライドします。


これは、ListBoxが自動的に表示されるため、ToStringのデータソースとしてタイプのリストを使用する場合に役立ちます。

別の状況は、ToStringを呼び出してタイプの表現を取得するString.Formatにタイプを渡したいときに発生します。

5
Jodrell

誰もまだ言及していないこと:ToString()をオーバーライドすることで、IFormattableの実装も検討できるため、次のことができます。

 public override ToString() {
   return string.Format("{0,-20} {1, -20}", m_work, m_personal);
 }

 public ToString(string formatter) {
   string formattedEmail = this.ToString();
   switch (formatter.ToLower()) {
     case "w":
       formattedEmail = m_Work;
       break;
     case "p":
       formattedEmail = m_Personal;
       break;
     case "hw":
       formattedEmail = string.Format("mailto:{0}", m_Work);
       break;
   }
   return formattedEmail;
}

これは便利です。

4

ToString()をオーバーライドする利点の1つは、Resharperのツールサポートです。Alt+ Ins-> "Formatting members"で、ToString()を書き込みます。

3

場合によっては、デバッガーウォッチウィンドウでカスタムクラスの値を読みやすくします。ウォッチウィンドウに表示する内容が正確にわかっている場合、その情報でToStringをオーバーライドすると、表示されます。

2
philologon

構造体(実質的にユーザープリミティブ)を定義するとき、ToString、およびParseおよびTryParseメソッドを一致させることをお勧めします。特にXMLシリアル化の場合。この場合、状態全体を文字列に変換し、後で読み取ることができるようにします。

ただし、クラスはToStringおよびParseを使用するには複雑すぎる通常の複合構造です。 ToStringメソッドは、状態全体を保存する代わりに、名前やIDなどの一意の識別子、またはリストの数量など、状態を識別するのに役立つ簡単な説明になります。

また、ロビーが言ったように、ToStringをオーバーライドすると、ToString型と同じくらい基本的な参照でobjectを呼び出すことができます。

1
Dave Cousineau

Object.ToStringメソッドは、デバッグ目的でのみ使用してください。デフォルトの実装では、あまり有用ではないオブジェクトタイプ名が表示されます。診断とデバッグのためにより良い情報を提供するために、このメソッドをオーバーライドすることを検討してください。ロギングインフラストラクチャは、多くの場合ToStringメソッドも使用するため、これらのテキストフラグメントはログファイルにあることを考慮してください。

Do notは、Object.ToString 方法。その理由は、ToStringメソッドは常に開発者が理解できるものを返す必要があるためです。開発者は、アプリケーションがサポートするすべての言語を話すとは限りません。

Implementユーザーフレンドリーなローカライズされたテキストを返したい場合、IFormattableインターフェースを実装します。このインターフェイスは、パラメータformatおよびformatProviderを使用してToStringオーバーロードを定義します。 formatProviderは、カルチャを意識した方法でテキストをフォーマットするのに役立ちます。

参照: Object.ToString and IFormattable

1
jbe

Personのような、文字列表現の直感的な意味を持たないオブジェクトがある場合に使用できます。そのため、たとえばこの人物を印刷する必要がある場合は、このオーバーライドを使用してその形式を準備できます。

1
NickF

他の回答で言及されているフレームワークガイドラインに満足しています。ただし、表示とデバッグの目的を強調したいと思います。

コードでToStringを使用する方法に注意してください。コードはオブジェクトの文字列表現に依存するべきではありません。存在する場合、それぞれのParseメソッドを絶対に提供する必要があります。

ToStringはどこでも使用できるため、後でオブジェクトの文字列表現を変更する場合、保守性の問題になる可能性があります。この場合、呼び出し階層を調べて、コードが破損するかどうかを調べることはできません。

0
tm1

シンプルは、プロパティの使用方法に依存します。文字列を一度だけフォーマットする必要がある場合、それをオーバーライドすることはあまり意味がありません。

ただし、ToStringメソッドをオーバーライドして、プロパティの通常の文字列データを返さず、標準のフォーマットパターンを実行しているようです。あなたはパディングでstring.formatを使用しているので。

学習していると言ったので、この演習は、カプセル化とコードの再利用に関連するオブジェクト指向プログラミングのコア原則にも当てはまるようです。

パディング用に設定した引数を取るstring.formatは、プロパティを呼び出すコードに対して毎回同じ方法でプロパティがフォーマットされるようにします。また、今後は、多くの場所ではなく1か所で変更するだけで済みます。

素晴らしい質問といくつかの素晴らしい答え!

0

エンティティクラスのToStringメソッドをオーバーライドすると、特にアサーションが失敗したときにテストコンソールがオブジェクトのToStringメソッドを呼び出すときにテストの問題をすばやく特定するのに役立ちます。

しかし、問題のオブジェクトの人間が読める表現を提供することになる前に言われたことに同意します。

0
ranjez