为 appsettings.json

问题描述

我想创建一个Symbols 转换为 IReadOnlyCollection<Symbol> 的 appsettings.json 转换器。转换器应按 / 拆分字符串,这将生成 BaseAsset/QuoteAsset。然后它应该检查 QuoteAsset 是否等于 StakeCurrency。如果没有,则抛出异常。使用自定义转换器执行此操作的最佳方法是什么?我不想使用绑定。是否可以使用自定义 JsonConverter?

  • appsettings.json
{
  "BacktestConfiguration": {
    "StakeCurrency": "USDT","Symbols": [ "TRX/USDT","BTC/USDT","ETH/USDT" ]
  }
}
  • 课程
public class BacktestOptions
{
    public const string Position = "BacktestConfiguration";

    public string StakeCurrency { get; set; }
    public IReadOnlyCollection<Symbol> Symbols { get; set; }
}

public class Symbol
{
    public string BaseAsset { get; set; }
    public string QuoteAsset { get; set; }
}

解决方法

您可以使用自定义 JsonConverter 来处理从字符串数组到 IReadOnlyCollection<Symbol> 的转换。

用转换器类型装饰 Symbols 类的 BacktestOptions 属性,并在自定义转换器的 Read() 方法中处理转换,在那里拆分数组中的字符串以生成新的 { {1}} 个带有零件的对象。
然后从生成的 Symbol 对象列表中返回一个新的 ReadOnlyCollection<Symbol>

我正在使用 handlerSymbol 来包含对象并提供基本转换和反序列化功能。

调用静态 BacktestConfigurationHandler 方法,将 JSON 作为参数传递。 当 StakeCurrency 值和任何 Symbol[].QuoteAsset 值之间没有不匹配时,它返回一个 Deserialize() 对象。
如果不匹配,它会抛出一个 BacktestConfiguration

称之为:

JsonException

var configuration = BacktestConfigurationHandler.Deserialize(json);

► 它只处理反序列化。如您所见,序列化并未实现:BacktestConfigurationHandler 方法什么也不做。

Write()

编辑:
尝试这些 Model 类的变体和适配的自定义转换器,包括 JSON 转换器和分配给 Symbols 属性的 TypeConverter。

我已经在基本场景中测试了转换器,直接从 JSON 转换为类模型,并使用 TypeConverter 调用的隐式运算符访问/转换对象。

public class BacktestConfigurationHandler
{
    public class BacktestRoot {
        public BacktestConfiguration BacktestConfiguration { get; set; }
    }

    public class BacktestConfiguration
    {
        public const string Position = "BacktestConfiguration";

        public string StakeCurrency { get; set; }

        [JsonConverter(typeof(SymbolConverter))]
        public IReadOnlyCollection<Symbol> Symbols { get; set; }
    }

    public class Symbol
    {
        public Symbol() : this("","") { }
        public Symbol(string baseAsset,string quoteAsset) {
            BaseAsset = baseAsset;
            QuoteAsset = quoteAsset;
        }

        public string BaseAsset { get; set; }
        public string QuoteAsset { get; set; }
    }

    public static BacktestConfiguration Deserialize(string json)
    {
        var root = JsonSerializer.Deserialize<BacktestRoot>(json);
        var stakeCurrency = root.BacktestConfiguration.StakeCurrency;
        if (root.BacktestConfiguration.Symbols.Any(s => s.QuoteAsset != stakeCurrency)) {
            throw new JsonException("StakeCurrency mismatch");
        }
        return root.BacktestConfiguration;
    }

    public class SymbolConverter : JsonConverter<IReadOnlyCollection<Symbol>>
    {
        public override IReadOnlyCollection<Symbol> Read(ref Utf8JsonReader reader,Type typeToConvert,JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.StartArray) {
                var symbols = new List<Symbol>();
                var values = JsonSerializer.Deserialize<string[]>(ref reader,options);

                foreach (string value in values) {
                    var parts = value.Split('/');
                    symbols.Add(new Symbol(parts[0],parts[1]));

                }
                return new ReadOnlyCollection<Symbol>(symbols);
            }
            return null;

        public override void Write(Utf8JsonWriter writer,IReadOnlyCollection<Symbol> value,JsonSerializerOptions options)
            => throw new NotImplementedException();
    }
}