ベストプラクティスを共有オブジェクト直列化さのカスタム文字列の形式で使用するための出力ファイル
-
19-09-2019 - |
質問
どうしてそうなっちゃうんですかつ実現しようとするオーバーライドのToString()特定のビジネスクラスを生産するためにエクセルフ形式の書き込むための出力ファイル、または後処理されます。このデータはように見え:
5555555 "LASTN SR, FIRSTN" 5555555555 13956 STREET RD TOWNSVILLE MI 48890 25.88 01-003-06-0934
でなければならないくだけで、書式文字列およびオーバーライド ToString()
, その変化の挙動 ToString()
のためのオブジェクトどうしたらよろしいですかにserializeこのように実施 ToString()
すべての不揃いの図書館があります。
現在、私は文発表会 IFormatProvider, し、実装するクラスまでの音のように良いアイデアがまだ少し戸惑いがすべてこの論理は居住者はどのようにフォーマッタクラスです。
どんなんな時に必要なものを、CSV、タブ区切りのテキストまたはその他の非XML任意の文字列のオブジェクト?
解決
ここではリフレクションを使用して、オブジェクトのリストからCSVを作成するための一般的な方法です。
public static string ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
Type t = typeof(T);
FieldInfo[] fields = t.GetFields();
string header = String.Join(separator, fields.Select(f => f.Name).ToArray());
StringBuilder csvdata = new StringBuilder();
csvdata.AppendLine(header);
foreach (var o in objectlist)
csvdata.AppendLine(ToCsvFields(separator, fields, o));
return csvdata.ToString();
}
public static string ToCsvFields(string separator, FieldInfo[] fields, object o)
{
StringBuilder linie = new StringBuilder();
foreach (var f in fields)
{
if (linie.Length > 0)
linie.Append(separator);
var x = f.GetValue(o);
if (x != null)
linie.Append(x.ToString());
}
return linie.ToString();
}
多くの変形が、このような)(ToCsvのファイルに直接書き出し、またはIEnumerableを、歩留まりステートメントでのStringBuilderを交換するように、作製することができる。
他のヒント
ここでは簡易版のHejndorfのCSVの考えなの架で利回りは各ライン)。により人気の需要にも対応し、両分野の簡単な特性を利用し Concat
.
更新月18日2017
この例では、たい対応できるようになって完全ソリューション、進むオリジナルのデザインが投稿したりHejndorf.を有効CSVへの交換が必要となりテキストの区切り文字以内の文字、配列の2つの区切り文字です。例えば簡単な .Replace("\"", "\"\"")
.
更新は12月2016年
使用後は自分のコードは再びプロジェクトは今日、今まず、何のために付与され始めた頃からの例 @Per Hejndorf
.こうしたデフォルトの区切り文字","(コンマ)の区切り文字の オプション, パラメータ.自分の図書館バージョンも提供3 header
パラメータにするかどうかを制御ヘッダ行を必要として返されることもありますよねだいています。
例えば
public static IEnumerable<string> ToCsv<T>(IEnumerable<T> objectlist, string separator = ",", bool header = true)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
if (header)
{
yield return String.Join(separator, fields.Select(f => f.Name).Concat(properties.Select(p=>p.Name)).ToArray());
}
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString())
.Concat(properties.Select(p=>(p.GetValue(o,null) ?? "").ToString())).ToArray());
}
}
で使用しますのでこうにカンマ区切り:
foreach (var line in ToCsv(objects))
{
Console.WriteLine(line);
}
またはこのような他の区切り文字(例えばTAB):
foreach (var line in ToCsv(objects, "\t"))
{
Console.WriteLine(line);
}
実施例
書リストをカンマ区切りCSVファイル
using (TextWriter tw = File.CreateText("C:\testoutput.csv"))
{
foreach (var line in ToCsv(objects))
{
tw.WriteLine(line);
}
}
たは書き込みでタブ区切り
using (TextWriter tw = File.CreateText("C:\testoutput.txt"))
{
foreach (var line in ToCsv(objects, "\t"))
{
tw.WriteLine(line);
}
}
ていれば複雑な分野/物性が必要となりまフィルターに選択条項.
以前のバージョンの詳細は以下:
ここでは簡易版のHejndorfのCSVの考えなの架で利回りは各ラインの回) やは4行のコード:)
public static IEnumerable<string> ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
FieldInfo[] fields = typeof(T).GetFields();
yield return String.Join(separator, fields.Select(f => f.Name).ToArray());
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString()).ToArray());
}
}
できる繰り返すようになります:
foreach (var line in ToCsv(",", objects))
{
Console.WriteLine(line);
}
場所 objects
は、強く型付けされたリストをサポートします。
この変化の両方が含まれ公共分野の簡単な公共性
public static IEnumerable<string> ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
yield return String.Join(separator, fields.Select(f => f.Name).Concat(properties.Select(p=>p.Name)).ToArray());
foreach (var o in objectlist)
{
yield return string.Join(separator, fields.Select(f=>(f.GetValue(o) ?? "").ToString())
.Concat(properties.Select(p=>(p.GetValue(o,null) ?? "").ToString())).ToArray());
}
}
私はデバッグのためのツールとしてのtoStringをオーバーライド提唱経験則として、それはビジネスロジックのためだ場合、それはクラス/インタフェース上の明示的な方法である必要があります。
このような単純な直列化のために私はシリアル化ではなく、ビジネスに連載を押してオブジェクト自体をんので、あなたのCSV出力ライブラリとあなたのビジネスオブジェクトを知っている別のクラスを持つことをお勧めしたい。
あなたのモデルのビューを生成し、出力形式ごとのクラスで終わるこの方法です。
あなたが永続化のためのオブジェクトグラフを書き込むしようとしているより複雑なシリアル化のために私は、ビジネスクラスでそれを置くことを検討したい - それはクリーンなコードになり場合にのみ、
。私がこれまでに見つかった解決策に伴う問題は、彼らはあなたがプロパティのサブセットが、唯一のオブジェクト全体をエクスポートすることはできませんということです。時間のほとんどは、我々はCSVでデータをエクスポートする必要があるとき、私たちは「テーラー」正確な方法でそのフォーマットする必要があり、私は私がに型Func<T, string>
のパラメータの配列を渡すことによってそれを行うことができますこの単純な拡張メソッドを作成しましたマッピングを指定します。
public static string ToCsv<T>(this IEnumerable<T> list, params Func<T, string>[] properties)
{
var columns = properties.Select(func => list.Select(func).ToList()).ToList();
var stringBuilder = new StringBuilder();
var rowsCount = columns.First().Count;
for (var i = 0; i < rowsCount; i++)
{
var rowCells = columns.Select(column => column[i]);
stringBuilder.AppendLine(string.Join(",", rowCells));
}
return stringBuilder.ToString();
}
の使用方法:の
philosophers.ToCsv(x => x.LastName, x => x.FirstName)
を生成します:の
Hayek,Friedrich
Rothbard,Murray
Brent,David
私は一つだけが読み込まれますでしょう、ハイテックマジックのばらつきが同じ値を持つ2つの性質た問題がありました。これは、それを修正しているようだ。
public static IEnumerable<string> ToCsv<T>(string separator, IEnumerable<T> objectlist)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
yield return String.Join(separator, fields.Select(f => f.Name).Union(properties.Select(p => p.Name)).ToArray());
foreach (var o in objectlist)
{
yield return string.Join(separator, (properties.Select(p => (p.GetValue(o, null) ?? "").ToString())).ToArray());
}
}
ゴーンのコーディング答えはとても役に立ちました。私は出力をホースうテキストグレムリンを処理するためにそれにいくつかの変更を加えます。
/******************************************************/
public static IEnumerable<string> ToCsv<T>(IEnumerable<T> objectlist, string separator = ",", bool header = true)
{
FieldInfo[] fields = typeof(T).GetFields();
PropertyInfo[] properties = typeof(T).GetProperties();
string str1;
string str2;
if(header)
{
str1 = String.Join(separator, fields.Select(f => f.Name).Concat(properties.Select(p => p.Name)).ToArray());
str1 = str1 + Environment.NewLine;
yield return str1;
}
foreach(var o in objectlist)
{
//regex is to remove any misplaced returns or tabs that would
//really mess up a csv conversion.
str2 = string.Join(separator, fields.Select(f => (Regex.Replace(Convert.ToString(f.GetValue(o)), @"\t|\n|\r", "") ?? "").Trim())
.Concat(properties.Select(p => (Regex.Replace(Convert.ToString(p.GetValue(o, null)), @"\t|\n|\r", "") ?? "").Trim())).ToArray());
str2 = str2 + Environment.NewLine;
yield return str2;
}
}