タイプのカスタムフォーマット文字列
入門
文字列は、おそらく最もよく使われるタイプで、ToStringメソッド()は、すべての最も使用される方法でなければなりません。しかし、それだけの種類の名前を出力するために使用すべきではない、適切に使用されている場合、それは簡単に出力フォーマット当社のカスタムタイプにすることができます。この記事では、ステップのToString()によってステップを論じ、そしてIFormattable、するIFormatProvider ICustomFormatterおよびインタフェースを関連します。
内部型のカスタム書式文字列を提供する能力
ToString System.Objectの基本クラスから継承されました()
文字列は、人々が直接、データタイプを読み取ることができ、多くの場合、我々は、出力の文字列型を得ることを期待するものです。したがって、Microsoft .NET Frameworkは、仮想のToString()メソッド内のSystem.Objectすべてのタイプの基本クラスを提供し、そのデフォルトの実装では、オブジェクトタイプの名前を返すことです。
我々は、オブジェクトのいくつかの情報「友人」を定義するようなタイプがあるとします。
名前空間CustomToString
パブリッククラスフレンド{
プライベート文字列FamilyNameで、//姓
プライベート文字列firstNameの; //名
パブリックフレンド(文字列FamilyNameで、文字列のfirstName){
this.familyName = FamilyNameで。
this.firstName = firstNameの;
}
パブリックフレンド():この( "张"、 "子阳"){}
パブリック文字列FamilyNameで{
FamilyNameで返す{得ます。}
}
パブリック文字列のFirstName {
{firstNameのを返し得ます。}
}
}
}
CustomToString.Friend:私たちは友達インスタンス上のToString()メソッドを呼び出すと、それは型の名前を返します。
新しい友達= Fフレンド();
Console.WriteLineを(f.ToString())。//输出:CustomToString.Friend
、toString()メソッドをカバー
かかわらず、インスタンス(オブジェクト)の種類のデータ(フィールド値)に含まれる上記の例では、それは常に同じ結果(CustomToString.Friend)を返します。私たちはそれの上に取得するために多くの場合、型名のオブジェクトを返すことはあまり意味がありません、私たちは、友人の名前(値famliyNameとのfirstNameフィールド)を返すことができることがより望ましいです。この時点で、我々は単に基底クラスのToString System.Objectの()メソッド、友達クラスを追加する方法を上書きすることができます。
//覆盖のSystem.Object基类的ToStringメソッド()方法
パブリックオーバーライド列のToString(){
String.Formatのリターン( "友人:{0} {1}"、FamilyNameで、firstNameの)を、
}
この時点で、我々は再びコードを実行します。
=新しい新しい友人フレンドF();
Console.WriteLineを(f.ToString()); //出力:友達:張Zaiyang
F =新しい友達( "キング"、 "タオ");
Console.WriteLineを(f.ToString()) ; //出力:友達:王タオ
あなたは、フィールドの値に基づいてのToString()オブジェクトは、異なる結果が返され、そう私たちのためにそれがより有意義になり、別のオブジェクトを見ることができます。
過負荷、toString()メソッド
時々、私たちはさまざまな方法でオブジェクトを書式設定する必要があるかもしれません。ある友人のタイプを取る:西洋では姓に続いて、最初の名前、および中国の人々、ポスト内の名前の元の名前です。だから、プログラムが間違って行くことはできませんが、ビューの言語学的観点から英語に問題があるものの、あなたは、次のコードを実行する場合:
友人A =新しい友達( "張"、 "ジミー");
Console.WriteLineを(a.ToString())。//输出:友達:ZhangJimmy
ジミー張:そして、我々は出力され期待しています。今回は、あなたが採用され、この問題への.NET Frameworkのソリューションについて考えてほしいことがあります。オーバーロードされたToStringメソッド()。ToStringメソッド()メソッドは、このパラメータに従ってフォーマットされ、一つのパラメータを取りましょう。¥123.00:そのようなINT = 123; Console.WriteLineを(a.ToString( "C")は)出力の貨幣タイプを生成する、パラメータとして文字列 "C" を指定します。パラメータに従ってフォーマットされた文字列を定義するように、我々はまた、友達のtoString()メソッドをオーバーロードし、友達のクラスを向上させるために、このメソッドを使用することができます。
//文字列パラメータは、フォーマットの種類に応じて定義されている
公共のString ToStringメソッド(文字列形式){
スイッチ(format.ToUpper()){
ケース"Wである":西:@西
戻りString.Formatの(「フレンド:{0 } 。1} { "firstNameの、FamilyNameで);
ケース" E "://イースト:オリエンタル
リターンthis.toString();
ケース" G「://一般的な
デフォルト:
(base.ToStringを返します);
}
}
その後、我々は、toString()メソッド、英語名を使用しているとき、私たちは、これは上記の問題を解決するだろう、パラメータとして「W」を渡すオーバーロードされたバージョンを使用することができます。
新しい友達= Fフレンド();
Console.WriteLineを(f.ToString())。//输出:友達:张子阳
F =新しい友達( "張"、 "ジミー");
Console.WriteLineを(f.ToString( "W")); //输出:友達:ジミー・チャン
注:この問題は、より良い解決策が過負荷にならないのToString()、あなたは、単にこのように、完了するために、プロパティを使用することができます。
パブリック文字列WesternFullNameは{
取得{String.Formatのを返す( "{0} {1}"、FirstNameとFamilyNameで)}
}
パブリック文字列EasternFullName {
取得{String.Formatのを返す( "{0} {1}"、FamilyNameで、firstNameの) }
}
この記事では、私はちょうど私がこのようにプロパティを使用する必要がありますので、気にし、決して説明しないように例を与えるためにここにいる、と背中は同じです。
IFormattableインターフェイスを実現
オーバーロードのToString()は文化の違い/イーストウエストにも対応することができますが、私たちは、友達のカテゴリをユーザーに提供するが、ユーザーのニーズは常に変化している:私たちは、型設計者の視点を考えるように立っています。例えば、ユーザはWeb開発者であり、名前が常に上)限り、彼は型のToString(に適用することになるでしょうとして、すべてのアウトし、各操作属性の形式を避けるために、太字で表示されていることが望ましいです所望の効果を達成するために、それは、次のような、いくつかのより簡単になります。
=新しい新しい友人友人F();
ます。Label1.Text = String.Formatの( "<B> {{0}} 1 </ B>。"、f.familyName、f.firstName);
//これは、より便利である(ユーザが希望):
//ます。Label1.Text = f.ToString(***)。
この時点で、私たちは本当の方法はありません方法をフォーマット提供します。不測の事態のために、我々は、ユーザーが文字列オブジェクトをフォーマットする方法を決定することができるようにしたいです。Microsoftは明らかに、この問題を考えて、私たちのためのインターフェイスIFormattableを提供します。あなたは、タイプデザイナーとして、望ましいユーザーのToStringメソッド()用のカスタム書式を提供するときは、このインタフェースを実装することができます。我々は今、このインターフェースの定義を見てみましょう。
パブリックインターフェイスIFormattable {
文字列のToString(文字列形式、formatProviderするIFormatProvider)。
}
それだけでメソッドToString()が含まれます。決定されたパラメータ値をフォーマットする方法については、format()メソッドのように私たちの前のセクションオーバーロードされたToStringメソッドと同じ意味を持つパラメータのフォーマットを、するIFormatProviderパラメータformatProviderのように定義されているタイプであり、次のように:
パブリックインターフェイスするIFormatProvider {
オブジェクトのgetFormat(タイプformatType)。
}
formatTypeは、オブジェクトタイプの現在のインスタンスであることを特徴と--typeオブジェクト(別の可能性は、ICustomFormatterある、後でが記載されています)。この例では、友人このタイプはフォーマットされ、この値は、等価formatTypeのtypeof演算(友人)、又はf.GetType()(Fフレンドタイプは一例である)です。構文getFormat()メソッドは、Object型のオブジェクトを返し、インターフェイスICustomFormatterを実装する形式のオブジェクトによって実行される実際の操作は、それが)(唯一の方法、フォーマットが含まれています。
パブリックインターフェイスICustomFormatter {
文字列形式(文字列形式、オブジェクト引数、formatProviderするIFormatProvider)。
}
上記と同じ形式の意味は、フォーマットの種類の引数としては、ここにある、請求一般的に本明細書で使用されていない友人、formatProviderの一例です。
再びICustomFormatterオブジェクトを取得するために最初のIFormatProvider.GetFormatパラメータプロバイダの()メソッドによって:タイプデザイナーとして、あなたはそれだけでIFormattableインターフェイスを実装する必要があります:あなたは覚えているあなたがいる限り、実際には、少し混乱を感じることがあり、ここを参照してください。次いで呼ICustomFormatterフォーマット()メソッドの更なる目的は、形式()メソッドの戻り値を返します。
パブリッククラスフレンド:IFormattable {
//略...
//实现IFormattable接口
公共の文字列ToStringメソッド(文字列形式、するIFormatProviderプロバイダー){
場合(!プロバイダ= NULL){
ICustomFormatterフォーマッタ=
provider.GetFormat(this.GetType())などICustomFormatter。
(フォーマッタ= nullで!)であれば
、戻りformatter.Format(フォーマット、この、プロバイダ);
}
this.ToString(フォーマット)を返します。
}
}
警告上記場所(this.GetType(よる))は、現在フレンドオブジェクト情報の種類のIFormatProvider.GetFormat()メソッドである内側通過します。
ここでの最後の仕事の種類のデザイナー、そして今、私たちはIFormattableのこのタイプを達成するために見てみましょう、オブジェクトの文字列形式の独自の定義を使用する方法をユーザーの種類。ユーザーのタイプとして、カスタム書式文字列オブジェクト、およびするIFormatProvider ICustomFormatterインターフェイスを実装する必要性を可能にするためです。この時点で、2つの戦略があります。
- このようなコールFriendFormatterとしてクラスの確立は、このクラスはするIFormatProviderとICustomFormatterインターフェイスを実装します。
- ICustomFormatterとするIFormatProviderインターフェイスを達成するために、それぞれ、このようなコールObjectFormatProviderとFriendFormatterのような2つのクラスを確立し、ましょう構文getFormat ObjectFormatProvider()メソッドは、FriendFormatterのインスタンスを返します。
のは、最初の戦略を見てみましょう:
パブリッククラスFriendFormatter:するIFormatProvider、ICustomFormatter {
//实现するIFormatProvider接口、由友人类的IFormattable.ToString()方法调用
パブリックオブジェクトのgetFormat(タイプformatType){
IF(formatType == typeof演算(友達))
、これを返します。
そうでない
場合はnull;
}
//实现ICustomFormatter接口
パブリック文字列形式(文字列形式、オブジェクト引数、formatProviderするIFormatProvider){
//もし(argがIFormattableある)
//リターン((IFormattable)引数).ToString(フォーマット、formatProvider)。
友達にargの友人の友人=;
もし(友人== nullの)
リターンarg.ToString();
スイッチ(format.ToUpper()){
ケースは、 "I":
String.Formatのを返す( "友人:<I> {0} {1} <I>"、friend.FamilyName、friend.FirstName)。
ケース"B":
戻りString.Formatの( "友人:<B> {0} {1} <B>"、friend.FamilyName、friend.FirstName)。
デフォルト:
)(arg.ToStringを返します。
}
}
}
ビューの上記結合、toString()メソッドは、ここでの処理は非常に明確である:この方法で使用されるとき、構文getFormatは文が、決定された場合(formatType == typeof演算(友人 )) オブジェクトの友人のFriendFormatterクラスタイプを確実にするために適用することができますフォーマット。その後、現在のFriendFormatterオブジェクトを返します。このキーワードで参照されます。FriendFormatter ICustomFormatterはまた、インタフェースを実装するので、タイプIFormattable.ToStringフレンド()メソッドは、FriendFormater ICustomFormatter型に変換され、次いで、所望の結果を返すようにICustomFormatter.Format()メソッドを呼び出すことができるからです。
注:、それのために実現ICustomFormattで何人かの人々の参照MSDNであってもよい、上部をコメントに注意し、文の一部を追加します。実際MSND例長いを用いて、String.Formatのを(使用)は形式をカスタマイズするためにオーバーロード、本明細書に変わります。あなたは上記のコメントをブロックすると、それは無限ループを形成することは明らかです。
私たちは今、上記のコードをテストするために見て:
新しい友達= Fフレンド();
FriendFormatterフォーマッタ=新しいFriendFormatter();
Console.WriteLineを(f.ToString( "B"、フォーマッタ))。//输出:友達:<B>张子阳</ B>
次は第二の方法、するIFormatProvider ICustomFormatterを見て、実装するために異なるクラスに引き渡さ:
ObjectFormatProviderクラスのパブリック:するIFormatProvider {
// ToStringメソッドによって呼び出さするIFormatProviderインターフェイスを実装する()クラスの友達の方法
パブリックオブジェクトのgetFormat(タイプformatType){
(formatType == typeof演算(フレンド))のIF
新しい新しいFriendFormatter()を返す;実現を返す// ICustomFormatterの種類の例としては
他に
戻りNULL;
}
}
// ICustomFormatterは、サービスのための特定のフォーマットを提供し、インターフェイスを実装する(例えば、友人)タイプ常に
パブリッククラスFriendFormatter:ICustomFormatter {
//実装インターフェイスICustomFormatter
パブリック文字列形式(文字列形式、オブジェクトをArgを、するIFormatProvider formatProvider){
// IF(IFormattable argはIS)
//リターン((IFormattable)のArg).ToString(フォーマット、formatProvider)。
友達にargの友人の友人=;
もし(友人== nullの)
リターンarg.ToString();
スイッチ(format.ToUpper()){
場合"I":
String.Formatの( "友達:<I> {0} {1} <I>"、friend.FamilyName、friend.FirstName)を返します。
ケース"B":
戻りString.Formatの( "友人:<B> {0} {1} <B>"、friend.FamilyName、friend.FirstName)。
デフォルト:
)(arg.ToStringを返します。
}
}
}
上記の方法はほぼ同じに見えますが、違いが2に、クラスの分割です。実際、二つのクラスに分割することは、より柔軟になります場合、FriendFormatter友達のみフォーマットタイプにクラスを使用する2つのインターフェイスの方法を実装します。私たちは、Bookクラスを持っている場合は、同様に、我々はBookFormatterを作成する必要があります。
そして、それは二つのクラスに分割され、もう一度ICustomFormatter、その後、ObjectFormatProviderそれに少し修正を行うインタフェースを実装するクラスを作成する必要があります。この時点で、Providerクラスは、フォーマットの複数のタイプのためのサービスを提供することができ、一般的なクラスとして見ることができます。今すぐ私たちは種類があると、私たちはそれだけでObjectFormatProviderクラスを変更する必要があります。
ObjectFormatProviderクラスのパブリック:するIFormatProvider {
// ToStringメソッドによって呼び出さするIFormatProviderインターフェイスを実装する()クラスの友達の方法
パブリックオブジェクトのgetFormat(タイプformatType){
(formatType == typeof演算(フレンド))のIF
新しい新しいFriendFormatter()を返す;
IFを(== formatType typeof演算(書籍))
)(新しい新しいBookFormatterを返す; //はBookFormatterターゲットを返し
、他の
戻り値null;
}
}
// ...省略形BookFormatter
外部のタイプにカスタム書式指定文字列を提供する能力
今、私たちは考えるようにユーザの視点の種類に立つ:多くの場合、設計者は、IFormattableインターフェイスタイプの種類を認識していなかった、そして我々はそれをどのように対処するのですか?私たちは、.NET Frameworkの治療について考えてみましょう:
INT A = 123。
Console.WriteLineを(a.ToString( "C")); //输出:¥123.00
Console.WriteLineを(String.Formatの( "{0:C}"、a)参照)。//输出:¥123.00
実際には、String.Formatのは()もオーバーロードされたメソッド、我々は必要な書式設定の効果のために、私たち自身するIFormatProviderによって定義されている受信するIFormatProviderオブジェクトを提供します。上記の比較によると、我々は要約を行いますカスタム書式指定文字列の種類を達成するために、我々は常にするIFormatProviderインターフェイスを実装する必要があります。タイプがIFormattableインターフェイスを実装している場合、我々はオブジェクトするIFormatProvider渡して、型のToString()メソッドを呼び出すことができます。IFormattableタイプがインタフェースを実装していない場合、私たちすることができます()静的メソッド、String.Formatの通過するIFormatProviderオブジェクトを渡します。
今、私たちはするIFormatProviderインターフェイスを実装し、途中いくつかのわずかに異なる上記のタイプを作成する必要があります。リフレクターツールによって(百度に行くことができるかわからない)見ることができ、(String.Formatのを呼び出す)と、内部のStringBuilder型を作成しますオブジェクトビルダー、次いでbuilder.AppendFormat(プロバイダ、フォーマット、引数)を呼び出し、このメソッド内で最終的に構文getFormat()メソッドのプロバイダを呼び出します。
フォーマッタ=(ICustomFormatter)provider.GetFormat(typeof演算(ICustomFormatter))。
あなたが見ることができる、provider.GetFormatは()typeof演算(ICustomFormatter)オブジェクトを通過しました。したがって、このようにString.FormatのするIFormatProvider()によって使用されるべきではない判断がされた場合に、外部のタイプのみ決定されていないformatType等しいtypeof演算(ICustomFormatter)があってもよいです。
OutFriendFormatterクラスパブリック:するIFormatProvider、ICustomFormatter
{
クラスのToStringによって実装//するIFormatProviderインターフェイスフレンド()メソッド呼び出し
のパブリックオブジェクトのgetFormat(タイプformatType)
{
IF(formatType == typeof演算(ICustomFormatter))
この戻り、
他の
リターンヌル;
}
/ / ICustomFormatterわずかに達成
}
もう一度、我々はコードのテストを見て:
新しい友達= Fフレンド();
OutFriendFormatterフォーマッタ=新しいOutFriendFormatter();
列出力= String.Formatの(フォーマッタ、 "{0:I}"、F)。
Console.WriteLineを(出力)。//友達:<I>张子阳<I>
ネットの例はするIFormatProviderを実装しました
最も一般的に使用されるの.NetするIFormatProviderの例では、CultureInfoクラスです。多くの場合、私たちが必要とする量は、その後、我々は通常、このように、フォーマットします:
int型、お金= 100;
Console.WriteLineを(String.Formatの( "{0:C}"、お金))。
私たちは、この出力の結果は¥100.00で期待しています。しかし、英語版のオペレーティングシステムでは、おそらく$ 100.00を得るでしょう。しかし、これはあなたが中国のオペレーティングシステム上でこのプログラムを実行すると、それは確かにあなたが望むように¥100.00を取得しますが、必ずしもそうではありません。あなたが明示的にそれが適切な表示へのデフォルトロケールで、ロケールを指定しますしない場合は量方式でデジタル表示で、現在のシステムのロケールに基づいて判断を下すためです。.NETで、クラスのロケールはのCultureInfoをカプセル化することであり、我々は明らかに完了するには、このクラスを利用することができ、どのように金額を指定する必要がある場合には、するIFormatProviderを実装します。
int型、お金= 100;
プロバイダ=新しいのCultureInfo( "ZH-CN")するIFormatProvider。
Console.WriteLineを(String.Formatの(プロバイダ、 "{0:C}"、お金))。//输出:¥100.00
プロバイダ=新しいのCultureInfo( "EN-US");
Console.WriteLineを(String.Formatの(プロバイダ、 "{0:C}"、お金))。//输出:$ 100.00
概要
この記事では、私は体系的なフォーマットの種類をカスタマイズする方法について説明します。、カバーのToString()、過負荷状態のToString()するIFormatProviderインターフェイスを実装しています。私たちは、この目的を達成するためのさまざまな方法があります。それらを実装するクラスを作成するか、それぞれが別のカテゴリを実装する:我々はまたするIFormatProviderとICustomFormatter二つの方法を議論しました。
なぜString.Formatの持つ3つのインタフェースを設計:私は多くの人が考えるように.NETフレームワークの設計者のポイントに、私たちが考えるように少しより多くのことができることを願っていますし、私はここを前に、これを読んで、これらのメソッドを使用すると思います()静的クラスは、このプロセスを実装するには?何このデザインは、柔軟性を提供しますか?この記事から、私はあなたがユーザーのためのフレームワークとしてではなく、このタイプの構造のためのフレームワークを設計するデザイナーとして、これらのタイプを使用する方法よりも多くの収穫を期待しています。
読書のためのおかげで、私はこの記事はあなたが助けて与えることができることを望みます!
ます。https://www.cnblogs.com/JimmyZhang/archive/2008/05/30/1210378.htmlで再現