【问题标题】:Generate C# classes from json schema with heterogeneous array使用异构数组从 json 模式生成 C# 类
【发布时间】:2017-09-19 00:19:23
【问题描述】:

我在一个项目中有一个 json 模式,并希望添加构建步骤以从中生成类,这些模式中包含一个对象和字符串数组,简化示例如下:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "testSchema",
    "type": "object",
    "properties": {
        "array": {
            "type": "array",
            "items": {
                "anyOf": [
                    {
                        "type": "string"
                    },
                    {
                        "type": "object",
                        "properties": {
                            "name": {
                                "type": "string"
                            }
                        }
                    }
                ]
            }
        }
    }
}

我正在使用NJsonSchema 从该架构生成 C# 代码。结果我得到以下输出:

//----------------------
// <auto-generated>
//     Generated using the NJsonSchema v8.32.6319.16936 (http://NJsonSchema.org)
// </auto-generated>
//----------------------

namespace TestSchema
{
#pragma warning disable // Disable all warnings

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class TestSchema : System.ComponentModel.INotifyPropertyChanged
{
    private System.Collections.ObjectModel.ObservableCollection<Anonymous> _array = new System.Collections.ObjectModel.ObservableCollection<Anonymous>();

    [Newtonsoft.Json.JsonProperty("array", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.ObjectModel.ObservableCollection<Anonymous> Array
    {
        get { return _array; }
        set 
        {
            if (_array != value)
            {
                _array = value; 
                RaisePropertyChanged();
            }
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    public string ToJson() 
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(this);
    }

    public static TestSchema FromJson(string data)
    {
        return Newtonsoft.Json.JsonConvert.DeserializeObject<TestSchema>(data);
    }

    protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class Anonymous : System.ComponentModel.INotifyPropertyChanged
{

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    public string ToJson() 
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(this);
    }

    public static Anonymous FromJson(string data)
    {
        return Newtonsoft.Json.JsonConvert.DeserializeObject<Anonymous>(data);
    }

    protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}
}

结果我有一个奇怪的Anonymous 类,如果我尝试反序列化下面的 json 文件,我会收到错误:string 无法转换为Anonymous。为了反序列化,我使用以下生成的方法:

TestSchema.FromJson

是否可以将代码生成调整为具有 object 的集合,并在其中获得具有正确类型的反序列化对象?

{
    "array": [
        "stringItem1",
        {
            "name": "complexObj1"
        }
    ]
}

【问题讨论】:

  • 我最喜欢的 JSON 到 C# 转换器是 json2csharp.com 我已经生成了你的 JSON,它看起来可以更好地表示你的 JSON 作为你的类。也许,它可以帮助你?

标签: c# json jsonschema njsonschema


【解决方案1】:

我终于实现了我所需要的。

想法是将自定义CSharpTypeResolver 传递给CSharpGenerator

new CSharpGenerator(jsonSchema4, settings, new CustomCSharpTypeResolver(settings, jsonSchema4), null);

看起来这不是 NJsonSchema 作者的意图。 在CustomCSharpTypeResolver 中,我覆盖Resolve 方法以添加以下行为:

if (schema.AnyOf.Count > 0)
    return "object";

作为简化示例的结果,我有以下模型:

//----------------------
// <auto-generated>
//     Generated using the NJsonSchema v8.32.6319.16936 (http://NJsonSchema.org)
// </auto-generated>
//----------------------

namespace JsonSchemaClassGenerator.TestSchema
{
#pragma warning disable // Disable all warnings

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class TestSchema : System.ComponentModel.INotifyPropertyChanged
{
    private System.Collections.ObjectModel.ObservableCollection<object> _array = new System.Collections.ObjectModel.ObservableCollection<object>();

    [Newtonsoft.Json.JsonProperty("array", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public System.Collections.ObjectModel.ObservableCollection<object> Array
    {
        get { return _array; }
        set 
        {
            if (_array != value)
            {
                _array = value; 
                RaisePropertyChanged();
            }
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    public string ToJson() 
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(this);
    }

    public static TestSchema FromJson(string data)
    {
        return Newtonsoft.Json.JsonConvert.DeserializeObject<TestSchema>(data);
    }

    protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "8.32.6319.16936")]
public partial class Object : System.ComponentModel.INotifyPropertyChanged
{
    private string _name;

    [Newtonsoft.Json.JsonProperty("name", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
    public string Name
    {
        get { return _name; }
        set 
        {
            if (_name != value)
            {
                _name = value; 
                RaisePropertyChanged();
            }
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    public string ToJson() 
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(this);
    }

    public static Object FromJson(string data)
    {
        return Newtonsoft.Json.JsonConvert.DeserializeObject<Object>(data);
    }

    protected virtual void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) 
            handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
}
}

反序列化工作正常。我可以随心所欲地投射物体。只有一个问题:对象被保存为JObject 实例,所以我需要实现explicitimplicit 运算符将其转换为生成的模型。

namespace JsonSchemaClassGenerator.TestSchema
{
    public partial class Object
    {
        public static implicit operator Object(JObject json)
        {
            return FromJson(json.ToString());
        }
    }
}

之后就可以将JObject 转换为生成的模型(Object 不是System.Object,它只是用这样的名称生成的):

Object a = config.Entries[1] as JObject;

这是我找到的最简单的解决方案。我认为也可以实现自定义CSharpTypeResolver 以获得更多类型安全的东西。但不确定我是否会尝试,因为对我来说,首先让NJsonSchema 更灵活似乎会更好。

【讨论】:

  • 我是 NJS 的作者。解析器旨在扩展以支持此类情况(请参阅github.com/NSwag/NSwag/blob/master/src/…)。如果您需要更多扩展点,请在 github 上创建问题,我们可以在那里讨论...
  • @RicoSuter 感谢您的反馈,会尝试这样做
猜你喜欢
  • 2013-03-24
  • 1970-01-01
  • 2014-11-29
  • 2013-03-08
  • 1970-01-01
  • 2011-02-06
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
相关资源
最近更新 更多