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

appsettings.json值转枚举失败抛InvalidOperationException的解决及替代方案

解决配置读取枚举时的转换异常及替代方案

一、修复枚举读取异常的方法

当配置值不在枚举定义范围内时,直接用GetValue<SubscriberKind?>会触发转换异常,可通过以下方式避免:

1. 安全转换枚举值

先读取配置的字符串值,再用Enum.TryParse尝试转换,转换失败时自定义处理逻辑:

internal static class ConfiguratorFactory
{
    public static ISubscriptionConfigurator Create(IConfiguration config)
    {
        var kindStr = config.GetValue<string>("Subscriber:Kind");
        if (!Enum.TryParse<SubscriberKind>(kindStr, out var subscriberKind))
        {
            throw new ArgumentException($"无效的订阅类型: {kindStr}", nameof(kindStr));
            // 也可返回默认配置器,或记录日志后抛出更友好的异常
        }

        return subscriberKind switch
        {
            SubscriberKind.UserTrades => new UserTrades.FtxConfigurator(config),
            _ => throw new ArgumentOutOfRangeException(nameof(subscriberKind))
        };
    }
}

2. 添加默认枚举项

在枚举中新增Unknown项作为转换失败的默认值,避免抛出异常:

public enum SubscriberKind
{
    Unknown,
    UserTrades
}

转换时使用带默认值的重载:

var kindStr = config.GetValue<string>("Subscriber:Kind");
Enum.TryParse<SubscriberKind>(kindStr, true, out var subscriberKind);

return subscriberKind switch
{
    SubscriberKind.UserTrades => new UserTrades.FtxConfigurator(config),
    SubscriberKind.Unknown => throw new ArgumentException($"无效的订阅类型: {kindStr}", nameof(kindStr)),
    _ => throw new ArgumentOutOfRangeException(nameof(subscriberKind))
};

二、无需枚举的替代实现方案

若想彻底避免枚举的限制(如新增类型需修改枚举定义),可采用以下方案:

1. 直接基于字符串匹配

跳过枚举,直接用配置中的字符串值匹配对应的配置器,扩展性更强:

internal static class ConfiguratorFactory
{
    public static ISubscriptionConfigurator Create(IConfiguration config)
    {
        var exchange = config.GetValue<string>("Subscriber:Exchange");
        var kindStr = config.GetValue<string>("Subscriber:Kind");

        return (exchange, kindStr) switch
        {
            ("ftx", "UserTrades") => new UserTrades.FtxConfigurator(config),
            ("ftx", "DropCopy") => new DropCopy.FtxConfigurator(config),
            // 新增订阅类型时,直接添加对应的分支即可
            _ => throw new ArgumentException($"不支持的订阅组合: Exchange={exchange}, Kind={kindStr}")
        };
    }
}

2. 策略模式+依赖注入

通过特性标记配置器支持的Exchange和Kind,结合DI容器自动发现配置器,实现完全解耦的扩展:

步骤1:定义特性

[AttributeUsage(AttributeTargets.Class)]
public class SubscriberConfiguratorAttribute : Attribute
{
    public string Exchange { get; }
    public string Kind { get; }

    public SubscriberConfiguratorAttribute(string exchange, string kind)
    {
        Exchange = exchange;
        Kind = kind;
    }
}

步骤2:标记配置器类

[SubscriberConfigurator("ftx", "UserTrades")]
public class FtxUserTradesConfigurator : ISubscriptionConfigurator
{
    public FtxUserTradesConfigurator(IConfiguration config)
    {
        // 初始化逻辑
    }
}

[SubscriberConfigurator("ftx", "DropCopy")]
public class FtxDropCopyConfigurator : ISubscriptionConfigurator
{
    public FtxDropCopyConfigurator(IConfiguration config)
    {
        // 初始化逻辑
    }
}

步骤3:实现工厂类

internal class ConfiguratorFactory
{
    private readonly IEnumerable<ISubscriptionConfigurator> _configurators;

    public ConfiguratorFactory(IEnumerable<ISubscriptionConfigurator> configurators)
    {
        _configurators = configurators;
    }

    public ISubscriptionConfigurator Create(IConfiguration config)
    {
        var exchange = config.GetValue<string>("Subscriber:Exchange");
        var kindStr = config.GetValue<string>("Subscriber:Kind");

        var configurator = _configurators.FirstOrDefault(c => 
        {
            var attr = c.GetType().GetCustomAttribute<SubscriberConfiguratorAttribute>();
            return attr != null && attr.Exchange == exchange && attr.Kind == kindStr;
        });

        if (configurator == null)
        {
            throw new ArgumentException($"不支持的订阅组合: Exchange={exchange}, Kind={kindStr}");
        }

        return configurator;
    }
}

这种方式下,新增订阅类型只需添加对应的配置器类并标记特性,无需修改工厂代码,符合开闭原则。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:10:23