C# 如何使用继承/多态性将JSON字符串解析为C对象?

C# 如何使用继承/多态性将JSON字符串解析为C对象?,c#,json,json.net,C#,Json,Json.net,我想将一个JSON字符串解析为一个可以是多态的C对象 总而言之:我不想实例化根对象,但我想根据JSON输入实例化继承的对象 下面是我使用的C对象的一个示例: public class Module { public string name; } public class Wheel : Module { public int amount; public Wheel(string name, int amount) : base(name) {...} } public clas

我想将一个JSON字符串解析为一个可以是多态的C对象

总而言之:我不想实例化根对象,但我想根据JSON输入实例化继承的对象

下面是我使用的C对象的一个示例:

public class Module {
  public string name;
}

public class Wheel : Module {
  public int amount;
  public Wheel(string name, int amount) : base(name) {...}
}

public class Break : Module {
  public double delay;
  public Break(string name, double delay) : base(name) {...}
}
我有一个JSON字符串,它是一个包含两个JSON对象的数组:

[{
  "name":"Wheel",
  "amount":4
},{
  "name":"Break",
  "delay":1.0
}]

我想将这个JSON字符串反序列化为C对象列表/数组。每个项目都应该被实例化为一个子类Wheel或Break,但由于列表项目必须位于同一分母上,因此列表类型必须是Module类型。

我认为您不可能一下子做到这一点。如果我必须这样做,我可能会这样做

var json = @"
[{
""name"":""Wheel"",
""amount"":4
},{
""name"":""Break"",
""delay"":1.0
}]";

// Get a list of possible types from the assembly containing Module.
// I don't know of a better way of doing this.
var types = typeof (Module).Assembly.GetTypes();

// Parse the original JSON into an array.
var joList = JArray.Parse(json);

// List I want to populate
var listModule = new List<Module>();

foreach (dynamic token in joList)
{
    string name = token.name;

    // Get the actual type.
    var type = types.FirstOrDefault(x=>x.Name == name);

    // If type is not found then continue.
    if (type == null)
        continue;

    // If type is not a subclass of Module, continue.
    if (!type.IsSubclassOf(typeof(Module)))
        continue;

    // Now deserialize that token into the actual type and add it to the list
    listModule.Add(JsonConvert.DeserializeObject(token.ToString(), type));

}
然后ReSharper将foreach循环中的所有代码转换成这个漂亮的小一行

var listModule = (from dynamic token in joList
    let name = token.name
    let type = types.FirstOrDefault(x => x.Name == (string) name)
    where type != null
    where type.IsSubclassOf(typeof (Module))
    select JsonConvert.DeserializeObject(token.ToString(), type)).Cast<Module>().ToList();
您需要这样做。

如果使用,您可以创建一些自定义转换器,如下所示:

public class ModuleObjectConverter : JsonCreationConverter<Module>
{
    protected override Module Create(Type objectType, JObject jObject)
    {
        // This is the important part - we can query what json properties are present
        // to figure out what type of object to construct and populate
        if (FieldExists("amount", jObject)) {
            return new Wheel();
        } else if (FieldExists("delay", jObject)) {
            return new Break();
        } else {
            return null;
        }
    }

    private bool FieldExists(string fieldName, JObject jObject)
    {
        return jObject[fieldName] != null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // We don't deal with writing JSON content, and generally Newtonsoft would make a good job of
        // serializing these type of objects without having to use a custom writer anyway
    }
}

// Generic converter class - could combine with above class if you're only dealing
// with one inheritance chain, but this way it's reusable
public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // Load JObject from stream
        JObject jObject = JObject.Load(reader);

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}
然后,在反序列化时,将此帮助程序的实例传递给Newtonsoft:

var modules = JsonConvert.DeserializeObject<List<Module>>(jsonString, new ModuleObjectConverter());

和这个问题的区别是什么?更清晰的描述,旧的已经被删除或者至少正在进行中。您是否尝试过Newtonsoft库?