gpt4 book ai didi

c# - Json.NET - 反序列化接口(interface)属性引发错误 "type is an interface or abstract class and cannot be instantiated"

转载 作者:行者123 更新时间:2023-12-05 04:44:11 30 4
gpt4 key购买 nike

我有一个类,它有一个接口(interface)属性。

public class Foo
{
public int Number { get; set; }

public ISomething Thing { get; set; }
}

尝试使用 Json.NET 反序列化 Foo 类时,出现如下错误消息:

无法创建 ISomething 类型的实例。类型是接口(interface)或抽象类,不能实例化。

来自类似的question ,我可以看到使用 TypeNameHandling = TypeNameHandling.Objects 将通过允许 Json.NET 在序列化时包含 .NET 类型名称来解决错误,从而知道需要将对象反序列化为哪个具体类型之后。

不过好像有caution advised当使用 TypeNameHandling.None 以外的 TypeNameHandling 值从外部源反序列化 JSON 时。

TypeNameHandling.Objects 显然属于这一类。

有没有办法在不引入任何安全风险的情况下反序列化具体对象类型(实现接口(interface))?

最佳答案

考虑到您没有确定要转换为哪种具体类型的字段,您唯一的解决方案是如您所述,TypeNameHandling = TypeNameHandling.Objects

但是,您可以缓解安全漏洞。

使用自定义 ISerializationBinder在序列化期间将 .NET 类型解析为类型名称并在反序列化期间将类型名称解析为 .NET 类型时验证传入的类型名称:

ConsoleAppSerializationBinder.cs

public class ConsoleAppSerializationBinder : ISerializationBinder
{
public Type BindToType(string? assemblyName, string typeName)
{
var resolvedTypeName = $"{typeName}, {assemblyName}";
return Type.GetType(resolvedTypeName, true);
}

public void BindToName(Type serializedType, out string? assemblyName, out string? typeName)
{
assemblyName = null;
typeName = serializedType.AssemblyQualifiedName;
}
}

JsonSerializerSettings object 上设置 SerializationBinder 属性到您的 Binder 实例,并使用与最初用于序列化数据的类型相同的 Binder 进行反序列化。

var jsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = new ConsoleAppSerializationBinder()
};

这里有一些演示工作代码来演示用法:

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var jsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
SerializationBinder = new ConsoleAppSerializationBinder()
};

var something1Input = new Foo
{
Number = 1,
Thing = new Something1
{
RandomNumber = 1,
RandomString = "test"
}
};

var something2Input = new Foo
{
Number = 1,
Thing = new Something2
{
RandomNumber = 2,
RandomBool = true
}
};

var something1Json = JsonConvert.SerializeObject(something1Input, jsonSerializerSettings);
var something2Json = JsonConvert.SerializeObject(something2Input, jsonSerializerSettings);

var something1 = JsonConvert.DeserializeObject<Foo>(something1Json, jsonSerializerSettings);
var something2 = JsonConvert.DeserializeObject<Foo>(something2Json, jsonSerializerSettings);

Console.WriteLine(something1.Thing.GetType());
Console.WriteLine(something2.Thing.GetType());
}

public class Foo
{
public int Number { get; set; }

public ISomething Thing { get; set; }
}

public interface ISomething
{
public int RandomNumber { get; set; }
}

public class Something1 : ISomething
{
public int RandomNumber { get; set; }
public string RandomString { get; set; }
}

public class Something2 : ISomething
{
public int RandomNumber { get; set; }
public bool RandomBool { get; set; }
}

public class ConsoleAppSerializationBinder : ISerializationBinder
{
public Type BindToType(string? assemblyName, string typeName)
{
var resolvedTypeName = $"{typeName}, {assemblyName}";
return Type.GetType(resolvedTypeName, true);
}

public void BindToName(Type serializedType, out string? assemblyName, out string? typeName)
{
assemblyName = null;
typeName = serializedType.AssemblyQualifiedName;
}
}
}
}

输出:

ConsoleApp.Program+Something1
ConsoleApp.Program+Something2

关于c# - Json.NET - 反序列化接口(interface)属性引发错误 "type is an interface or abstract class and cannot be instantiated",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69433958/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com