【C#】エンティティクラスから一部のプロパティのみをCSV出力したい(カスタム属性使用)

 エンティティクラスのプロパティにカスタム属性を付けて、その属性を基にCSVへ出力をします。

また、カスタム属性には、出力順とヘッダーテキストを設定できるようにします。


①カスタム属性クラスをつくります。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class CSVExportAttribute : Attribute
{
/// <summary>
/// CSVへの出力順です。
/// </summary>
public int OutputID { get; private set; }
/// <summary>
/// カラムのヘッダーテキストです。
/// </summary>
public string ColumnsHeaderText { get; private set; }
/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="outputID">CSVへの出力順を指定してください。</param>
/// <param name="columnHeaderText">カラムのヘッダーテキストを指定してください。</param>
public CSVExportAttribute(int outputID, string columnHeaderText)
{
OutputID = outputID;
ColumnsHeaderText = columnHeaderText;
}
}
view raw CustomAttribute hosted with ❤ by GitHub

今回のカスタム属性はプロパティ向けなので、ターゲットをAttributeTargets.Propertyに。

多重設定を許さないので、AllowMultiple = falseに。

継承は必要ないので、Inherited = falseに。


②エンティティクラス(適当)を用意して、出力したいプロパティにカスタム属性を設定します。

public class SourceEntity
{
[CSVExport(1, "管理番号")]
public int SourceID { get; set; }
public DateTime RegistDate { get; set; }
[CSVExport(2,"苗字")]
public string FirstName { get; set; } = string.Empty;
[CSVExport(3,"名前")]
public string LastName { get; set; } = string.Empty;
public int Age { get; set; }
[CSVExport(5,"数学の偏差値")]
public int MathematicalDeviationValue { get; set; }
[CSVExport(6,"科学の偏差値")]
public int ScienceDeviationValue { get; set; }
[CSVExport(8,"英語の偏差値")]
public int EnglishDeviationValue { get; set; }
[CSVExport(4,"国語の偏差値")]
public int JapaneseDeviationValue { get; set; }
[CSVExport(7,"社会の偏差値")]
public int SocialDeviationValue { get; set; }
}
view raw Entity hosted with ❤ by GitHub

※超適当でごめんなさい。


③動作確認のため、エンティティクラスに適当に値を設定します。

// 動作確認用のエンティティを作成します。
var entities = new List<SourceEntity>()
{
{ new SourceEntity{ SourceID=1, RegistDate=DateTime.Now, Age=16, FirstName="ichiro", LastName="yamada",
EnglishDeviationValue=50, JapaneseDeviationValue=50, MathematicalDeviationValue=50, ScienceDeviationValue=50, SocialDeviationValue=50} },
{ new SourceEntity{ SourceID=2, RegistDate=DateTime.Now, Age=15, FirstName="jiro", LastName="suzuki",
EnglishDeviationValue=60, JapaneseDeviationValue=45, MathematicalDeviationValue=55, ScienceDeviationValue=55, SocialDeviationValue=40} },
{ new SourceEntity{ SourceID=3, RegistDate=DateTime.Now, Age=16, FirstName="saburo", LastName="honda",
EnglishDeviationValue=45, JapaneseDeviationValue=40, MathematicalDeviationValue=60, ScienceDeviationValue=60, SocialDeviationValue=40} },
{ new SourceEntity{ SourceID=4, RegistDate=DateTime.Now, Age=17, FirstName="shiro", LastName="matsuda",
EnglishDeviationValue=65, JapaneseDeviationValue=65, MathematicalDeviationValue=60, ScienceDeviationValue=65, SocialDeviationValue=65} },
{ new SourceEntity{ SourceID=5, RegistDate=DateTime.Now, Age=14, FirstName="goro", LastName="toyoda",
EnglishDeviationValue=40, JapaneseDeviationValue=45, MathematicalDeviationValue=45, ScienceDeviationValue=40, SocialDeviationValue=40} }
};
view raw CreateEntities hosted with ❤ by GitHub

※ここからは、エンティティクラスを使用する任意のクラス、処理内に記載しています。


④カスタム属性が設定されたプロパティのみを抽出して、出力順を昇順に並び替えます。

// CSVExportAttributeが設定されたプロパティを取得します。
var exportProperties = typeof(SourceEntity).GetProperties().Where(e => Attribute.IsDefined(e, typeof(CSVExportAttribute))).ToList();
// 出力するプロパティが無ければ処理終了します。
if (exportProperties == null || exportProperties.Count == 0)
return false;
// OutputIDの値で並び替えます。
exportProperties = exportProperties.OrderBy(e => ((CSVExportAttribute)Attribute.GetCustomAttribute(e, typeof(CSVExportAttribute))).OutputID).ToList();
view raw GetProperties hosted with ❤ by GitHub

もう少しスマートなLinqの使い方が… .Where(...).OrderBy(...).Select(...)で書けばよいと思うの。


⑤カスタム属性のヘッダーテキストと出力データを抽出します。

// ヘッダーテキストを取得します。
var headerTextList = exportProperties.Select(e => ((CSVExportAttribute)Attribute.GetCustomAttribute(e, typeof(CSVExportAttribute))).ColumnsHeaderText).ToList();
// 出力対象の実データを取得します。
var exportVales = new List<List<string>>();
foreach(var entity in entities)
{
var element = exportProperties.Select(e => typeof(SourceEntity).GetProperty(e.Name).GetValue(entity).ToString()).ToList();
exportVales.Add(element);
}

※ここでは、エンティティの各プロパティもList<string>として格納していますが、お好きな様にしてください。


⑥取り出した値をカンマ区切りでテキストファイルに出力します。

ソースは特別載せませんが、今回はList<List<string>>で渡していますので、1レコードの文字列リストをカンマでつないで1行として出力をしています。

※参考:出力結果

管理番号,苗字,名前,国語の偏差値,数学の偏差値,科学の偏差値,社会の偏差値,英語の偏差値
1,ichiro,yamada,50,50,50,50,50
2,jiro,suzuki,45,55,55,40,60
3,saburo,honda,40,60,60,40,45
4,shiro,matsuda,65,60,65,65,65
5,goro,toyoda,45,45,40,40,40
view raw ResultCSV hosted with ❤ by GitHub


※動作確認はVS2022(preview)/.Net6(preview)です。


コメント

このブログの人気の投稿

【C#】ComboBoxのデータソースにディクショナリを設定したい

【C#】いつもLog4netの設定を忘れる

【C#】2つのコンボボックスを使って、コンボボックスソースを切り替えたい