简体   繁体   English

将 JSON 反序列化为具有泛型类型参数的接口列表

[英]Deserialization of JSON to List of Interface with generic type parameter

As the title mentions, I am trying to deserialize a JSON but am having some trouble.正如标题所提到的,我正在尝试反序列化 JSON,但遇到了一些麻烦。 I think below includes the necessary information.我认为下面包括必要的信息。

public class Variable<T> : IVariable where T : IConvertible
{
    //...
}

public class ArrayVariable<T> : IVariable where T : IConvertible
{
    //...
}

So I have a list of IVariable which I then serialize successfully (all of the information is in the json):所以我有一个 Ivariable 列表,然后我成功地序列化了它(所有信息都在 json 中):

JsonConvert.SerializeObject(myIVariableList)

Now I am trying to deserialize it but I am having trouble determining the correct way to go about doing it as it involves finding the generic type T in addition to the type Variable or ArrayVariable .现在我正在尝试反序列化它,但我无法确定正确的方法来执行它,因为除了类型VariableArrayVariable之外,它还涉及找到泛型类型T I have already tried我已经试过了

JsonConvert.DeserializeObject<List<IVariable>>(result.newValues)

but obviously, you can create instances of an interface.但显然,您可以创建接口的实例。 Any help would be much appreciated.任何帮助将非常感激。

You can use TypeNameHandling.All to add type information to your serialiazed json and then utilize it during parsing:您可以使用TypeNameHandling.All将类型信息添加到序列化的 json 中,然后在解析过程中使用它:

var variables = new List<IVariable>()
{
    new Variable<int>()
};
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var serializeObject = JsonConvert.SerializeObject(variables, settings);
var list = JsonConvert.DeserializeObject<List<IVariable>>(serializeObject, settings);

You can use TypeNameHandling.All but I would strongly recommend you avoid it due to it being very dangerous and allows attackers to compromise your code .您可以使用TypeNameHandling.All但我强烈建议您避免使用它,因为它非常危险并且允许攻击者破坏您的代码

Another safer option is to use a custom converter.另一个更安全的选择是使用自定义转换器。 Here's a very trivial (and fragile) example that should get you started:这是一个非常简单(且脆弱)的示例,可以帮助您入门:

First lets make some basic classes that share an interface:首先让我们创建一些共享接口的基本类:

public interface IVariable { }

public class Foo : IVariable
{
    public int A { get; set; }
}

public class Bar : IVariable
{
    public int B { get; set; }
}

Now we can make our converter:现在我们可以制作我们的转换器:

public class IVariableConverter : JsonConverter<IVariable>
{
    public override IVariable ReadJson(JsonReader reader, Type objectType, 
        IVariable existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // First load the JSON into a JObject
        var variable = JObject.Load(reader);

        // If the JSON had a property called A, it must be a Foo:
        if (variable.ContainsKey("A"))
        {
            return variable.ToObject<Foo>();
        }

        // If the JSON had a property called B, it must be a Bar:
        if (variable.ContainsKey("B"))
        {
            return variable.ToObject<Bar>();
        }

        // And who knows what was passed in if it was missing both of those properties?!
        throw new Exception("Er, no idea what that JSON was supposed to be!");


    }

    public override void WriteJson(JsonWriter writer, IVariable value, 
        JsonSerializer serializer)
    {
        // Feel free to write your own code here if you need it
        throw new NotImplementedException();
    }
}

And now we can do some actual deserialising:现在我们可以做一些实际的反序列化:

// A basic JSON example:
var json = "[{\"A\":1},{\"B\":2}]";

// The settings to tell the serialiser how to process an IVariable object
var settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new IVariableConverter() }
};

// And deserialise with the defined settings
var result = JsonConvert.DeserializeObject<List<IVariable>>(json, settings);

You will need to be a bit more creative with how you identify each type, but this is a safe way to achieve what you need.您将需要在如何识别每种类型方面更具创造性,但这是实现您需要的安全方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM