You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何向实现ITypeConverter的CustomDecimalConverter类注入服务类?

解决思路与实现步骤

1. 给转换器添加构造函数注入

修改CustomDecimalConverter,通过构造函数接收所需服务,避免硬编码实例化:

public class CustomDecimalConverter : ITypeConverter
{
    private readonly IDecimalRangeService _rangeService;

    // 构造函数注入服务
    public CustomDecimalConverter(IDecimalRangeService rangeService)
    {
        _rangeService = rangeService;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var inputStr = value?.ToString().Trim();
        if (string.IsNullOrEmpty(inputStr))
        {
            // 按需处理空值,返回null或默认decimal值
            return default(decimal);
        }

        // 处理OVR+/-标记
        if (inputStr.Equals("OVR+", StringComparison.OrdinalIgnoreCase))
        {
            // 通过parameter传递目标列的decimal类型定义,如"decimal(5,1)"
            return _rangeService.GetMaxValue(parameter.ToString());
        }
        else if (inputStr.Equals("OVR-", StringComparison.OrdinalIgnoreCase))
        {
            return _rangeService.GetMinValue(parameter.ToString());
        }

        // 正常转换小数
        if (decimal.TryParse(inputStr, NumberStyles.Any, culture, out var result))
        {
            return result;
        }

        throw new InvalidOperationException($"无法转换值 {inputStr} 为decimal类型");
    }
}

2. 实现范围计算服务

创建服务类处理decimal(x,y)格式的最大/最小值计算:

public interface IDecimalRangeService
{
    decimal GetMaxValue(string decimalTypeDefinition);
    decimal GetMinValue(string decimalTypeDefinition);
}

public class DecimalRangeService : IDecimalRangeService
{
    public decimal GetMaxValue(string decimalTypeDefinition)
    {
        // 解析decimal(x,y)格式字符串
        var regexMatch = Regex.Match(decimalTypeDefinition, @"decimal\((\d+),(\d+)\)", RegexOptions.IgnoreCase);
        if (!regexMatch.Success)
        {
            throw new ArgumentException($"无效的decimal类型定义: {decimalTypeDefinition}");
        }

        int totalDigits = int.Parse(regexMatch.Groups[1].Value);
        int decimalPlaces = int.Parse(regexMatch.Groups[2].Value);
        int integerDigits = totalDigits - decimalPlaces;

        // 拼接最大数值字符串
        string integerPart = new string('9', integerDigits);
        string decimalPart = new string('9', decimalPlaces);

        return decimal.Parse($"{integerPart}.{decimalPart}", CultureInfo.InvariantCulture);
    }

    public decimal GetMinValue(string decimalTypeDefinition)
    {
        // 最小值为最大值的负数
        return -GetMaxValue(decimalTypeDefinition);
    }
}

3. 配置框架使用依赖注入创建转换器

不同框架的配置方式略有差异,以下是常见场景的示例:

场景一:使用CsvHelper处理CSV

自定义TypeConverterFactory从DI容器获取转换器实例:

public class DiTypeConverterFactory : ITypeConverterFactory
{
    private readonly IServiceProvider _serviceProvider;

    public DiTypeConverterFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public ITypeConverter GetConverter(Type type)
    {
        // 针对decimal类型使用自定义转换器
        if (type == typeof(decimal))
        {
            return _serviceProvider.GetRequiredService<CustomDecimalConverter>();
        }
        // 其他类型使用默认转换器
        return TypeConverterFactory.Default.GetConverter(type);
    }
}

注册服务并使用:

// 在Program.cs/Startup.cs中注册服务
services.AddScoped<IDecimalRangeService, DecimalRangeService>();
services.AddScoped<CustomDecimalConverter>();

// 初始化CsvReader时配置自定义工厂
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    TypeConverterFactory = new DiTypeConverterFactory(serviceProvider)
};

using var reader = new StreamReader("your-data.csv");
using var csv = new CsvReader(reader, config);

// 映射时传递decimal类型参数
csv.Context.RegisterClassMap<YourCsvMap>();

public class YourCsvMap : ClassMap<YourCsvModel>
{
    public YourCsvMap()
    {
        Map(m => m.TargetDecimalColumn)
            .ConvertUsing<CustomDecimalConverter>("decimal(5,1)");
    }
}

场景二:使用AutoMapper映射到数据库实体

配置AutoMapper从DI容器构造转换器:

// 注册服务
services.AddScoped<IDecimalRangeService, DecimalRangeService>();
services.AddScoped<CustomDecimalConverter>();
services.AddAutoMapper(cfg =>
{
    // 让AutoMapper通过DI创建转换器实例
    cfg.ConstructServicesUsing(type => serviceProvider.GetService(type));
    
    cfg.CreateMap<CsvRowModel, DbEntity>()
        .ForMember(dest => dest.TargetDecimalColumn, 
            opt => opt.ConvertUsing<CustomDecimalConverter, string>("decimal(5,1)"));
});

4. 补充说明

  • 若需自动获取实体列的decimal类型定义,可在服务中添加反射逻辑,读取EF Core的ColumnAttribute的TypeName属性,无需手动传递参数。
  • 根据业务需求调整异常处理逻辑,比如对无效输入返回默认值而非抛出异常。

内容的提问来源于stack exchange,提问作者kidbabic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:35:16