为 appsettings.json 编写自定义转换器

nop*_*nop 5 c# appsettings jsonconverter

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

  • 应用程序设置.json
{
  "BacktestConfiguration": {
    "StakeCurrency": "USDT",
    "Symbols": [ "TRX/USDT", "BTC/USDT", "ETH/USDT" ]
  }
}
Run Code Online (Sandbox Code Playgroud)
  • 课程
{
  "BacktestConfiguration": {
    "StakeCurrency": "USDT",
    "Symbols": [ "TRX/USDT", "BTC/USDT", "ETH/USDT" ]
  }
}
Run Code Online (Sandbox Code Playgroud)

Jim*_*imi 4

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

\n

使用转换器 Type 修饰类Symbols的属性BacktestOptions,并在自定义转换器的方法中处理转换Read(),在该方法中,您可以拆分数组中的字符串以生成Symbol带有各个部分的新对象。\n然后从生成的对象列表中
返回一个新的。ReadOnlyCollection<Symbol>Symbol

\n

我使用处理程序类BacktestConfigurationHandler来包含对象并提供基本转换和反序列化功能。

\n

调用静态Deserialize()方法,传递 JSON 作为参数。\nBacktestConfiguration当 StakeCurrency 值与任何 Symbol[].QuoteAsset 值之间不存在不匹配时,它会返回一个对象。
\nJsonException如果不匹配,它会抛出 a 。

\n

称其为:

\n
var configuration = BacktestConfigurationHandler.Deserialize(json);\n
Run Code Online (Sandbox Code Playgroud)\n

BacktestConfigurationHandler班级

\n

\xe2\x96\xba 它仅处理反序列化。如您所见,序列化未实现:该Write()方法不执行任何操作。

\n
public class BacktestConfigurationHandler\n{\n    public class BacktestRoot {\n        public BacktestConfiguration BacktestConfiguration { get; set; }\n    }\n\n    public class BacktestConfiguration\n    {\n        public const string Position = "BacktestConfiguration";\n\n        public string StakeCurrency { get; set; }\n\n        [JsonConverter(typeof(SymbolConverter))]\n        public IReadOnlyCollection<Symbol> Symbols { get; set; }\n    }\n\n    public class Symbol\n    {\n        public Symbol() : this("", "") { }\n        public Symbol(string baseAsset, string quoteAsset) {\n            BaseAsset = baseAsset;\n            QuoteAsset = quoteAsset;\n        }\n\n        public string BaseAsset { get; set; }\n        public string QuoteAsset { get; set; }\n    }\n\n    public static BacktestConfiguration Deserialize(string json)\n    {\n        var root = JsonSerializer.Deserialize<BacktestRoot>(json);\n        var stakeCurrency = root.BacktestConfiguration.StakeCurrency;\n        if (root.BacktestConfiguration.Symbols.Any(s => s.QuoteAsset != stakeCurrency)) {\n            throw new JsonException("StakeCurrency mismatch");\n        }\n        return root.BacktestConfiguration;\n    }\n\n    public class SymbolConverter : JsonConverter<IReadOnlyCollection<Symbol>>\n    {\n        public override IReadOnlyCollection<Symbol> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n        {\n            if (reader.TokenType == JsonTokenType.StartArray) {\n                var symbols = new List<Symbol>();\n                var values = JsonSerializer.Deserialize<string[]>(ref reader, options);\n\n                foreach (string value in values) {\n                    var parts = value.Split('/');\n                    symbols.Add(new Symbol(parts[0], parts[1]));\n\n                }\n                return new ReadOnlyCollection<Symbol>(symbols);\n            }\n            return null;\n\n        public override void Write(Utf8JsonWriter writer, IReadOnlyCollection<Symbol> value, JsonSerializerOptions options)\n            => throw new NotImplementedException();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n
public class BacktestOptionsRoot\n{\n    public BacktestOptions BacktestConfiguration { get; set; }\n}\n\npublic class BacktestOptions\n{\n    public const string Position = "BacktestConfiguration";\n\n    public string StakeCurrency { get; set; }\n\n    [JsonConverter(typeof(JsonSymbolConverter))]\n    [TypeConverter(typeof(BacktestSymbolsConverter))]\n    public BacktestSymbols Symbols { get; set; }\n}\n\npublic class Symbol\n{\n    public Symbol() : this("", "") { }\n    public Symbol(string baseAsset, string quoteAsset)\n    {\n        BaseAsset = baseAsset;\n        QuoteAsset = quoteAsset;\n    }\n\n    public string BaseAsset { get; set; }\n    public string QuoteAsset { get; set; }\n}\n\npublic class BacktestSymbolsConverter : TypeConverter\n{\n    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)\n    {\n        if (destinationType == typeof(string[])) {\n            return (BacktestSymbols)(value as string[]);\n        }\n        return base.ConvertTo(context, culture, value, destinationType);\n    }\n\n    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)\n    {\n        if (value is BacktestSymbols) {\n            return (string[])(value as BacktestSymbols);\n        }\n        return base.ConvertFrom(context, culture, value);\n    }\n}\n\npublic class JsonSymbolConverter : JsonConverter<BacktestSymbols>\n{\n    public override bool CanConvert(Type typeToConvert)\n    {\n        return typeToConvert == typeof(BacktestSymbols);\n    }\n\n    public override BacktestSymbols Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        if (reader.TokenType == JsonTokenType.StartArray) {\n            return JsonSerializer.Deserialize<string[]>(ref reader, options);\n        }\n        return null;\n    }\n\n    public override void Write(Utf8JsonWriter writer, BacktestSymbols value, JsonSerializerOptions options)\n    {\n        throw new NotImplementedException();\n    }\n}\n\n\npublic class BacktestSymbols\n{\n    public ReadOnlyCollection<Symbol> Value { get; }\n    public string[] Symbols => Value.Select(v => $"{v.BaseAsset}/{v.QuoteAsset}").ToArray();\n\n    public BacktestSymbols(string[] source)\n    {\n        var symbols = new List<Symbol>();\n\n        if (source != null && source.Length > 0) {\n            foreach (string value in source) {\n                var parts = value.Split('/');\n                symbols.Add(new Symbol(parts[0], parts[1]));\n            }\n        }\n        Value = new ReadOnlyCollection<Symbol>(symbols);\n    }\n\n    public static implicit operator BacktestSymbols(string[] source) => new BacktestSymbols(source);\n    public static implicit operator string[](BacktestSymbols instance) => instance.Symbols;\n    public override string ToString() => $"[ {string.Join(",", Symbols)} ]";\n}\n
Run Code Online (Sandbox Code Playgroud)\n