将json反序列化为接口的简洁方法?

时间:2016-09-28 11:14:41

标签: c# .net json json.net

我有一个配置服务,它包装了已烘焙的程序集设置,但我也想在命令行上覆盖它们。 目前这段代码工作正常:

    public interface ISettings
    {
        string Url { get; }
    }

    public class OperationalSettings : ISettings
    {
        public string Url { get { return ServiceSettings.Default.Url; } }
    }

    public class CommandLineModel
    {
        public string Url;
    }

    public class CommandLineSettings : ISettings
    {
        private readonly CommandLineModel _model;

        public CommandLineSettings(string serialisedSettings)
        {
            _model = JsonConvert.DeserializeObject<CommandLineModel>(serialisedSettings);
        }

        public string Url { get { return _model.Url; } }
    }

    public class ConfigService
    {
        private readonly ISettings _settings;
        public ConfigService(ISettings settings)
        {
            _settings = settings;
        }
        public ISettings settings { get { return _settings; } }
    }

然后是测试驱动程序代码:

 class Program
    {
        static void Main(string[] args)
        {
            ISettings opSettings = new OperationalSettings();

            var commandLineTest = "{Url:'http://overridenurl.com'}";

            ISettings commandSettings = new CommandLineSettings(commandLineTest);

            var configService = new ConfigService(opSettings);
            var configServiceUsingCmdOpts = new ConfigService(commandSettings);
        }
    }

因此,我可以使用命令行字符串覆盖设置。但是,我不喜欢的是,如果我有新设置,我现在需要在4个地方添加:

  • 界面
  • 设置包装器(OperationalSettings)的具体实现
  • 反序列化的命令行模型
  • 包装反序列化模型的命令行设置实现。

一旦我添加了更多属性,这似乎会受到可伸缩性的影响。如果没有这么多的代码更改,是否有更有效的方法来实现这一目标?

1 个答案:

答案 0 :(得分:0)

您可以查看DynamicObject

  public class CommandLineModelDictionary : DynamicObject
    {
        // The inner dictionary.
        Dictionary<string, object> dictionary
            = new Dictionary<string, object>();

        // This property returns the number of elements
        // in the inner dictionary.
        public int Count
        {
            get
            {
                return dictionary.Count;
            }
        }

        // If you try to get a value of a property 
        // not defined in the class, this method is called.
        public override bool TryGetMember(
            GetMemberBinder binder, out object result)
        {
            // Converting the property name to lowercase
            // so that property names become case-insensitive.
            string name = binder.Name.ToLower();

            // If the property name is found in a dictionary,
            // set the result parameter to the property value and return true.
            // Otherwise, return false.
            return dictionary.TryGetValue(name, out result);
        }

        // If you try to set a value of a property that is
        // not defined in the class, this method is called.
        public override bool TrySetMember(
            SetMemberBinder binder, object value)
        {
            // Converting the property name to lowercase
            // so that property names become case-insensitive.
            dictionary[binder.Name.ToLower()] = value;

            // You can always add a value to a dictionary,
            // so this method always returns true.
            return true;
        }
    }

否则如果您有一个简单的场景,您需要一个只能在运行时添加和删除成员但不需要定义特定操作且没有静态成员的对象,请使用ExpandoObject

这里如何使用

class Program
    {
        public static dynamic Dyn { get; set; }

        static void Main(string[] args)
        {
          dynamic model= new  CommandLineModelDictionary();
            model.Prop1 = "Foo";
            model.Prop2 = "toto";  



             Console.WriteLine(model.Prop1);
            Console.WriteLine(model.Prop2);
            //otherwise you can use 
            dynamic dynModel = new ExpandoObject();
            dynModelop1 = "Test1";
            dynModel2 = "Test2";  
            Console.WriteLine(dynModel.Prop1);
            Console.WriteLine(dynModel.Prop2);


        }
    }