我正在尝试使用Json创建一个配置文件,该文件将保存各种类型对象的配置。
考虑这个文件:
{
"cameras": [
{
"type": "Some.Namespace.CameraClass",
"assembly": "Some.Assembly",
"configuration": {
"ip": "127.0.0.1",
"port": 8080
}
}
]
}
在运行时,我将使用两个“type”和“assembly”属性来构造支持特定接口的对象,然后我想将配置加载到该对象中。
但是,在编译时我不知道“配置”将映射到的类型。我想将它保留为json“属性”并将其保存到相机对象中,然后让该对象将json反序列化为正确的类型。
因此我想将包含特定相机类型配置的配置文件的一部分“随身携带”到对象本身,并让它处理它,当我携带它时将其视为黑盒子像那样。应该保留该部分的结构,因为在为每个摄像机实现创建配置类型时我想要完全保真,甚至在必要时添加子对象。
对于这个特定的相机,我会配置一个IP地址和一个端口,对于其他一些相机,我需要授权数据,而对于其他一些相机则完全不同。
我希望保持这种配置的属性能够直接获取Json,仍然是一个字符串。
这可能吗?
这是一个LINQPad示例,其中有一些位被注释掉:
void Main()
{
const string configurationFile = @"[
{
""type"": ""UserQuery+Camera1"",
""configuration"": { ""id"": 10 }
},
{
""type"": ""UserQuery+Camera2"",
""configuration"": { ""name"": ""The second camera"" }
}
]";
var cameras = JsonConvert.DeserializeObject<Camera[]>(configurationFile);
foreach (var camera in cameras)
{
var type = Type.GetType(camera.Type);
var instance = Activator.CreateInstance(type, new object[0]) as ICamera;
// instance.Configure(camera.Configuration);
}
}
public class Camera
{
public string Type { get; set; }
public JObject Configuration { get; set; }
}
public interface ICamera
{
void Configure(string json);
}
public class Camera1 : ICamera
{
private class Configuration
{
public int Id { get; set; }
}
public void Configure(string json)
{
JsonConvert.DeserializeObject<Configuration>(json).Dump();
}
}
public class Camera2 : ICamera
{
private class Configuration
{
public string Name { get; set; }
}
public void Configure(string json)
{
JsonConvert.DeserializeObject<Configuration>(json).Dump();
}
}
两个注释掉的位,即Camera
类中的属性,以及对Configure
方法的调用,是我想要的。
有什么东西可以标记该属性,或者我可以为该属性选择的其他类型,这会使这个工作吗?
我知道我可以将属性设置为动态,这会将JObject
填入其中,但每个相机实现的每个Configure
方法都必须处理JObject
而不是一种已知的非动态类型。
答案 0 :(得分:9)
看起来如果使用类型为JObject
的属性,它会解析但保留JSON:
using System;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class Foo
{
public string Name { get; set; }
public int Age { get; set; }
public JObject Configuration { get; set; }
}
public class Test
{
public static void Main()
{
var json = File.ReadAllText("test.json");
var foo = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine(foo.Configuration);
}
}
Test.json:
{
"name": "Jon",
"age": 10,
"configuration": {
"ip": "127.0.0.1",
"port": 8080
}
}
输出:
{
"ip": "127.0.0.1",
"port": 8080
}
我怀疑您可以直接从JObject
反序列化,但如果您愿意,可以随时将其转换回string
。
答案 1 :(得分:-1)
如果第二级配置只是一个字符串:
{
"cameras": [
{
"type": "Some.Namespace.CameraClass",
"assembly": "Some.Assembly",
"configuration": "{ \"ip\": \"127.0.0.1\", \"port\": 8080 }"
}
]
}
这映射到一个类:
public class Camera
{
public string Type { get; set; }
public string Assembly { get; set; }
public string Configuration { get; set; }
}
然后你可以进行第二级反序列化,如你问题中已经显示的那样。