dooo

得意分野よりも、勉強中の内容を書きたい

属性ベースのCSV出力

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.IO;
using System.Text;

namespace CsvWriter
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var basicList = new List<ICsvFieldsDto>();

                for (int i = 0; i < 10; i++)
                {
                    var basic = new BasicDto();
                    basic.Id = i.ToString();
                    basic.Name = "Name" + i;
                    basic.Memo = "Memo" + i;

                    basicList.Add(basic);
                }

                var csvWriter = new CsvWriter();
                csvWriter.Write(basicList, "example.csv", false);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.Write("終了");
            Console.Read();
        }
    }

    /// <summary>
    /// CSV書き込み
    /// </summary>
    class CsvWriter
    {
        internal void Write(List<ICsvFieldsDto> csvFieldsDtoList, string path, bool appends)
        {
            List<List<string>> csvRecords = csvFieldsDtoList.Select(csvFieldsDto => GetCsvFieldValueListByProperties(csvFieldsDto)).ToList();

            using (var sw = new StreamWriter(path, appends))//, Encoding.GetEncoding("shift_jis")))
            {
                csvRecords.ForEach(record =>
                {
                    sw.WriteLine(String.Join(",", record));
                });
            }
        }

        /// <summary>
        /// 引数のDTOのCsvFied属性の付いたプロパティの値を、CSV出力におけるフィールド順の値のリストに変換
        /// </summary>
        /// <returns>CSV出力におけるフィールド順の値のリスト</returns>
        /// <param name="csvFieldsDto">CSVFieldsDtoインターフェースを実装したクラス</param>
        private List<string> GetCsvFieldValueListByProperties(ICsvFieldsDto csvFieldsDto)
        {
            // CSVFied属性の付いたプロパティを指定された順番でリストする
            var csvFieldProperties = csvFieldsDto.GetType()
                               .GetProperties()
                               .Where(property => property.GetCustomAttributes(typeof(CsvFieldAttribute), true).Length > 0)
                                                 .OrderBy(property => ((CsvFieldAttribute)property.GetCustomAttributes(typeof(CsvFieldAttribute), true).First()).Order);

            if (!csvFieldProperties.All(csvProperty => csvProperty.PropertyType == typeof(string)))
            {
                // string型のみCSV出力の対象とする
                throw new InvalidOperationException("String type is only valid for CsvField.");
            }

            // 特定文字の置換・削除を行い、ダブルクォート付加をしたうえで、値のリストにして返却
            var csvFields = csvFieldProperties.Select(property =>
            {
                var value = (string)property.GetValue(csvFieldsDto);

                var csvFieldAttr = (CsvFieldAttribute)property.GetCustomAttributes(typeof(CsvFieldAttribute)).First();

                if (csvFieldAttr.NeedsCharReplacing)
                {
                    // 要件に定められた文字の置換
                }

                if (csvFieldAttr.NeedsCharRemoving)
                {
                    // 要件に定められた文字の削除
                }

                return "\"" + value + "\"";
            }).ToList();

            return csvFields;
        }
    }

    /// <summary>
    /// CSVのフィールドをプロパティとして持つことを表すマーカーインターフェース
    /// </summary>
    /// <remarks>
    /// CSVのフィールドとして出力したいstring型のpublicなプロパティにCsvField属性を付与してください。
    /// </remarks>
    interface ICsvFieldsDto { }

    /// <summary>
    /// CSV出力の対象フィールドであることを示すAttribute
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    class CsvFieldAttribute : Attribute
    {
        /// <summary>
        /// 何番目のフィールドか
        /// </summary>
        /// <value>The order.</value>
        public int Order { get; set; }

        /// <summary>
        /// 置換が必要な文字が存在するか
        /// </summary>
        /// <value><c>true</c> if needs char replacing; otherwise, <c>false</c>.</value>
        public bool NeedsCharReplacing { get; set; }

        /// <summary>
        /// 削除が必要な文字が存在するか
        /// </summary>
        /// <value><c>true</c> if needs char replacing; otherwise, <c>false</c>.</value>
        public bool NeedsCharRemoving { get; set; }

        public CsvFieldAttribute(int order)
        {
            this.Order = order;
        }
    }

    /// <summary>
    /// DTO Example
    /// </summary>
    class BasicDto : ICsvFieldsDto
    {
        [CsvField(1)]
        public string Id { set; get; }
        [CsvField(2)]
        public string Name { set; get; }
        [CsvField(3, NeedsCharReplacing = true)]
        public string Memo { set; get; }
    }
}