【问题标题】:Deserialization of JSON to List of Interface with generic type parameter将 JSON 反序列化为具有泛型类型参数的接口列表
【发布时间】:2021-10-19 14:52:37
【问题描述】:

正如标题所述,我正在尝试反序列化 JSON,但遇到了一些麻烦。我认为下面包含了必要的信息。

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

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

所以我有一个 IVariable 列表,然后我成功序列化(所有信息都在 json 中):

JsonConvert.SerializeObject(myIVariableList)

现在我正在尝试反序列化它,但我无法确定正确的执行方法,因为除了类型 VariableArrayVariable 之外,它还涉及查找泛型类型 T。我已经试过了

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

但显然,您可以创建接口的实例。任何帮助将不胜感激。

【问题讨论】:

  • 显然你不能从界面创建实例——你几乎回答了你的问题。您甚至不能从抽象类创建实例。使用具体的 lass 而不是接口。 Json 反序列化器不会创建匿名类型。如果需要匿名类型,请使用 Parse。

标签: c# json deserialization


【解决方案1】:

您可以使用TypeNameHandling.All,但我强烈建议您避免使用它,因为它是very dangerous and allows attackers to compromise your code

另一个更安全的选择是使用自定义转换器。这是一个非常微不足道(且脆弱)的示例,应该可以帮助您入门:

首先让我们创建一些共享接口的基本类:

public interface IVariable { }

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

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

现在我们可以制作转换器了:

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();
    }
}

现在我们可以进行一些实际的反序列化:

// 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);

您需要在识别每种类型方面更有创意,但这是实现您需要的安全方法。

【讨论】:

  • 谢谢大卫!这真的帮助了我 :) 我根据我的特殊情况对其进行了修改,它就像一个魅力:D 我唯一添加的是这样的东西(对不起格式,不知道如何格式化评论?):( IVariable)typeof(IVariableConverter).GetMethod("ConvertToArrayVariable").MakeGenericMethod(typeof(double)).Invoke(this, new object[] { variable }); and... public IVariable ConvertToArrayVariable(JObject variable) where T : IConvertible { return variable.ToObject>(); }
【解决方案2】:

您可以使用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);

【讨论】:

  • 我会避免使用TypeNameHandling.All,它非常危险。
猜你喜欢
  • 1970-01-01
  • 2015-05-03
  • 2020-11-19
  • 2017-12-23
  • 1970-01-01
  • 2019-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多