Addressオブジェクトを文字列に変換する最良の方法は何ですか?
質問
プロパティAddressLine1、AddressLine2、Suburb、State、ZipCodeを持つAddressオブジェクトがあります。 (他にもありますが、この例ではこれで十分です)。また、これらのプロパティはそれぞれ文字列です。そして、私はC#3.0を使用しています。
それを文字列として表現したいのですが、そのようにすると、すべてのifステートメントのために、循環的複雑度の高いメソッドを作成していることに気づきます...
各プロパティに割り当てられた文字列がプロパティの名前と同じであると仮定します(つまり、AddressLine1 =" AddressLine1")...アドレスを次のように表します:
" AddressLine1 AddressLine2郊外州郵便番号"。
今、私がこれを行った最初の方法は、単純なString.Format()によるものでした
String.Format("{0} {1} {2} {3} {4}", address.AddressLine1,
address.AddressLine2, address.Suburb, address.State, address.ZipCode);
これは、これらのフィールドの一部が空であることが判明するまで、特にAddressLine2で問題ありません。その結果、不要なスペースが追加されます。これは、いくつかの行を連続して取得すると特に迷惑になります。
この問題を回避し、考えられる唯一の解決策として、文字列を手動で作成し、nullまたは空でない場合にのみ文字列にアドレスプロパティを追加する必要がありました。
ie
string addressAsString = String.Empty;
if (!String.IsNullOrEmpty(address.AddressLine1))
{
addressAsString += String.Format("{0}", address.AddressLine1);
}
if(!String.IsNullOrEmpty(address.AddressLine2))
{
addressAsString += String.Format(" {0}", address.AddressLine2);
}
etc....
これを達成するために、私が考えていないよりエレガントで簡潔な方法はありますか?私の解決策は厄介で肥大化しているように感じます...しかし、私はそれを行うためのより良い方法を考えることができません...
私が知っているすべての人にとって、これは私がやりたいことを考えると私の唯一のオプションです...良い選択肢がなければ、それで...まあでも、もしあれば、今まで知らなかったことを学ぶことになります。
事前に感謝します!
解決
これはおそらく最も効率的な方法ではありませんが、簡潔です。必要なアイテムを配列に入れ、重要な値のないアイテムをフィルターで除外してから、それらを結合できます。
var items = new[] { line1, line2, suburb, state, ... };
var values = items.Where(s => !string.IsNullOrEmpty(s));
var addr = string.Join(" ", values.ToArray());
おそらくより効率的ですが、多少読みにくいのは、値を StringBuilder
に集約することです。例:
var items = new[] { line1, line2, suburb, state, ... };
var values = items.Where(s => !string.IsNullOrEmpty(s));
var builder = new StringBuilder(128);
values.Aggregate(builder, (b, s) => b.Append(s).Append(" "));
var addr = builder.ToString(0, builder.Length - 1);
私はおそらく最初の実装のようなものに傾いていますが、それははるかにシンプルで保守性の高いコードであり、パフォーマンスが問題である場合は、2番目の実装に似たものを検討します(結果がより高速になる場合... )。
(これにはC#3.0が必要ですが、言語バージョンについては言及しないため、これで問題ないと思います)
他のヒント
文字列をまとめるときは、StringBuilderクラスを使用することをお勧めします。これは、System.Stringが不変であるため、文字列に変更を加えるたびに新しい文字列が返されるだけです。
オブジェクトをテキストで表現したい場合は、ToString()メソッドをオーバーライドして、実装をそこに配置することをお勧めします。
最後になりましたが、C#3.5のLinqでは、Greg Beechがここでやったようにそれらを結合できますが、string.Join()を使用する代わりに:
StringBuilder sb = new StringBuilder();
foreach (var item in values) {
sb.Append(item);
sb.Append(" ");
}
これがお役に立てば幸いです。
ToStringメソッドをオーバーライドし、カスタムタイプを定義するIFormatProvider実装を使用することをお勧めします。
MSDNの http://msdn.microsoft.com/を参照してください。 IFormatProviderの実装については、en-us / library / system.iformatprovider.aspx を参照してください。
次のようなコードを作成できます。
address.ToString(" s"); //短い住所
address.ToString(" whatever"); //定義したカスタム形式。
間違いなく最も簡単な方法ではありませんが、最もクリーンなIMHOです。そのような実装の例は、DateTimeクラスです。
乾杯
アッシュ
まず、住所には特定の情報が必要なので、郵便番号などのない住所は許可しないでください。また、各プロパティを空の文字列に初期化するか、コンストラクターへの引数として各プロパティを要求することで、それらがnullにならないようにすることもできます。これにより、有効なデータをすでに処理していることがわかるので、IsNullOrEmptyチェックを必要とせずに、フォーマットされた文字列を出力できます。
複数行の連絡先の要約を作成する際に、いくつかの空のフィールドが存在する可能性がある同様の問題がありました。文字列に何度も連結し続けないように文字列ビルダーを使用したことを除いて、私はあなたがしたこととほとんど同じことをしました。
データが完全に信頼できない場合は、そのロジックをどこかに持つ必要があります-そのロジックを実行する別の読み取り専用プロパティ(FormattedAddressなど)を作成することをお勧めします。そうすれば、コードを変更する必要はありません。ある時点で、クリーンアップするか、ルールを変更します。
さらに、文字列を連結するのではなく、文字列ビルダーを使用することを提案する+1。
これは本当に古いことを知っていますが、一般的な解決策を感じ、このように実装しました:
private static string GetFormattedAddress(
string address1,
string address2,
string city,
string state,
string zip)
{
var addressItems =
new []
{
new[] { address1, "\n" },
new[] { address2, "\n" },
new[] { city, ", " },
new[] { state, " " },
new[] { zip, null }
};
string suffix = null;
var sb = new StringBuilder(128);
foreach (var item in addressItems)
{
if (!string.IsNullOrWhiteSpace(item[0]))
{
// Append the last item's suffix
sb.Append(suffix);
// Append the address component
sb.Append(item[0]);
// Cache the suffix
suffix = item[1];
}
}
return sb.ToString();
}