【问题标题】:CsvHelper Format Decimal using ClassMapCsvHelper 使用 ClassMap 格式化十进制
【发布时间】:2020-07-13 12:21:08
【问题描述】:

我在文件中有列的列,这些列将具有需要使用 CsvHelper ClassMap 转换为“1200.00”之类的值,例如“000120000”。我目前对这些列使用 Decimal 类型,并且 ClassMap 中的 NumberStyle 在开头截断了零。所以我得到的值为“120000”。我尝试使用“TypeConverterOption.Format("0.00")”但没有运气。所以想知道是否有一种方法可以使用 ClassMap 将值“120000”转换为“1200.00”。我什至可以除以 100,但不想在我使用该字段的任何地方都这样做,因此需要在 ClassMap 中执行此逻辑。提前感谢您在这方面帮助我。

在 ClassMap 中我有以下代码: csvConfig.TypeConverterOptionsCache.GetOptions().NumberStyle = NumberStyles.Number | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent;

例如:“000120000”->“1200.00”(现在我得到的值是“120000”)

【问题讨论】:

    标签: csvhelper


    【解决方案1】:

    这是您可以做到的一种方式。使用自定义转换器。

    public class Program
    {
        static void Main(string[] args)
        {
            using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            using (var reader = new StreamReader(stream))
            using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
            {
                writer.WriteLine("Id,MoveDecimalPoint,NoMoveDecimalPoint");
                writer.WriteLine("1,000120000,000120000");
                writer.Flush();
                stream.Position = 0;
    
                csv.Configuration.RegisterClassMap<FooClassMap>();
    
                var records = csv.GetRecords<Foo>().ToList();
            }
        }
    }
    
    public class Foo
    {
        public int Id { get; set; }
        public decimal MoveDecimalPoint { get; set; }
        public decimal NoMoveDecimalPoint { get; set; }
    }
    
    public class FooClassMap : ClassMap<Foo>
    {
        public FooClassMap()
        {
            AutoMap(CultureInfo.InvariantCulture);
            Map(m => m.MoveDecimalPoint).TypeConverter<MoveDecimalConverter>();
        }
    }
    
    public class MoveDecimalConverter : DecimalConverter
    {
        public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
        {
            var numberStyle = memberMapData.TypeConverterOptions.NumberStyle ?? NumberStyles.Number;
    
            if (decimal.TryParse(text, numberStyle, memberMapData.TypeConverterOptions.CultureInfo, out var d))
            {
                return d / 100;
            }
    
            return base.ConvertFromString(text, row, memberMapData);
        }
    }
    

    如果您想让所有十进制值移动两位小数,您可以将MoveDecimalConverter 添加到配置中。

    public class Program
    {
        static void Main(string[] args)
        {
            using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            using (var reader = new StreamReader(stream))
            using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
            {
                writer.WriteLine("Id,MoveDecimalPoint,NoMoveDecimalPoint");
                writer.WriteLine("1,000120000,000120000");
                writer.Flush();
                stream.Position = 0;
    
                csv.Configuration.TypeConverterCache.AddConverter<decimal>(new MoveDecimalConverter());
    
                var records = csv.GetRecords<Foo>().ToList();
            }
        }
    }
    

    你也可以使用ConvertUsing()

    public class Program
    {
        static void Main(string[] args)
        {
            using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            using (var reader = new StreamReader(stream))
            using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
            {
                writer.WriteLine("Id,MoveDecimalPoint,NoMoveDecimalPoint");
                writer.WriteLine("1,000120000,000120000");
                writer.Flush();
                stream.Position = 0;
    
                csv.Configuration.RegisterClassMap<FooClassMap>();
    
                var records = csv.GetRecords<Foo>().ToList();
            }
        }
    }
    
    public class Foo
    {
        public int Id { get; set; }
        public decimal MoveDecimalPoint { get; set; }
        public decimal NoMoveDecimalPoint { get; set; }
    }
    
    public class FooClassMap : ClassMap<Foo>
    {
        public FooClassMap()
        {
            AutoMap(CultureInfo.InvariantCulture);
            Map(m => m.MoveDecimalPoint).ConvertUsing(row =>
            {
                if (decimal.TryParse(row["MoveDecimalPoint"], NumberStyles.Number, row.Configuration.CultureInfo, out var d))
                {
                    return d / 100;
                } 
                else
                {
                    return 0;
                }
            });
        }
    }
    

    【讨论】:

    • 这很有帮助,谢谢大卫。您知道实现所需输出的任何其他方法吗?
    • 我添加了一个ConvertUsing() 示例。最终,我相信您将不得不手动除以 100。您无法使用任何格式。格式化只会格式化您拥有的数字。您需要将数字转换为原始数字大小的 1/100。
    • 您的另一种选择是进行字符串操作并在您想要的小数位置放置一个句点,然后使用decimal.Parsedecimal.TryParse
    • 仅供参考。如果您希望所有十进制值移动小数位,您可以使用第一个示例并且您不需要FooClassMap。只需将csv.Configuration.RegisterClassMap&lt;FooClassMap&gt;(); 替换为csv.Configuration.TypeConverterCache.AddConverter&lt;decimal&gt;(new MoveDecimalConverter());
    • 我仍然必须使用 FooClassMap,因为还有其他字段需要以不同方式从文件中读取。所以我想第一个例子会很好用。需要对文本进行一些空值检查,然后进行十进制解析。感谢您对此问题的意见。
    猜你喜欢
    • 1970-01-01
    • 2013-07-29
    • 1970-01-01
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    相关资源
    最近更新 更多