首页 > 解决方案 > CsvHelper 使用 ClassMap 格式化十进制

问题描述

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

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

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

标签: csvhelper

解决方案


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

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;
            }
        });
    }
}

推荐阅读