我正在尝试使用Json创建配置文件,该文件将保存各种类型对象的配置.
考虑这个文件:
{ "cameras": [ { "type": "Some.Namespace.CameraClass","assembly": "Some.Assembly","configuration": { "ip": "127.0.0.1","port": 8080 } } ] }
在运行时,我将使用两个“类型”和“程序集”属性来构造支持特定接口的对象,然后我想将配置加载到该对象中.
但是,在编译时我不知道“配置”将映射到的类型.我想将它保留为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而不是已知的非动态类型.
解决方法
看起来如果你使用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反序列化,但如果你真的想,你总是可以将它转换回字符串.