【问题标题】:Dynamically add nested property to ExpandoObject将嵌套属性动态添加到 ExpandoObject
【发布时间】:2012-11-30 22:16:49
【问题描述】:

我正在获取一个 JSON 对象(可能包含多个级别的 JSON 数组等),我想将其转换为 ExpandoObject。

我想出了如何在运行时向 ExpandoObject 添加简单的属性,因为它实现了 IDictionary,但是如何在运行时添加 嵌套 属性(例如,myexpando.somelist.anotherlist.someitem 会正确解决吗?

编辑:目前这适用于简单(第一级)属性:

var exo = new ExpandoObject() as IDictionary<String, Object>;
exo.Add(name, value);

问题是如何获取要嵌套的名称以及如何相应地解析 ExpandoObject。

【问题讨论】:

  • Alex,考虑到您之前的问题,我认为您需要 DynamicObject 而不是 ExpandoObject。请参阅this 及其samples

标签: c# dynamic expandoobject


【解决方案1】:
dynamic myexpando = new ExpandoObject();
myexpando.somelist = new ExpandoObject() as dynamic;
myexpando.somelist.anotherlist = new ExpandoObject() as dynamic;
myexpando.somelist.anotherlist.someitem = "Hey Hey There! I'm a nested value :D";

【讨论】:

    【解决方案2】:

    这样做怎么样:

    var exo = new ExpandoObject() as IDictionary<String, Object>;
    var nested1 = new ExpandoObject() as IDictionary<String, Object>;
    
    exo.Add("Nested1", nested1);
    nested1.Add("Nested2", "value");
    
    dynamic d = exo;
    Console.WriteLine(d.Nested1.Nested2); // Outputs "value"
    

    【讨论】:

      【解决方案3】:

      当调用TryGetValue 时,您可以通过存储对先前检索到的对象或字典的引用来做到这一点。我使用的类如下所示:

      public DynamicFile(IDictionary<string, object> dictionary)
      {
          if (dictionary == null)
              throw new ArgumentNullException("dictionary");
          _dictionary = dictionary;
          _lastGetRef = _dictionary;
      }
      
      private readonly IDictionary<string, object> _dictionary;
      private IDictionary<string, object> _lastGetRef;
      
      public override bool TryGetMember(GetMemberBinder binder, out object result)
      {
          if (!_dictionary.TryGetValue(binder.Name, out result))
          {
              result = null;
              return true;
          }
      
          var dictionary = result as IDictionary<string, object>;
          if (dictionary != null)
          {
              result = new DynamicFile(dictionary);
              _lastGetRef = dictionary;
              return true;
          }
      
          return true;
      }
      
      public override bool TrySetMember(SetMemberBinder binder, object value)
      {
          if(_dictionary.ContainsKey(binder.Name))
              _dictionary[binder.Name] = value;
          else if (_lastGetRef.ContainsKey(binder.Name))
              _lastGetRef[binder.Name] = value;
          else
              _lastGetRef.Add(binder.Name, value);
      
          return true;
      }
      

      _dictionary 在创建动态对象时由构造函数设置,然后设置为直接最后一个引用字典。这是因为字典是类,因此是引用类型。

      为了正确嵌套,您需要在每个嵌套级别实例化每个字典,就像多维数组一样。例如:

      myexpando.somelist = new Dictionary<string, object>();
      myexpando.somelist.anotherlist = new Dictionary<string, object>();
      myexpando.somelist.anotherlist.someitem = "Hey Hey There! I'm a nested value :D";
      

      您可能可以在TryGetMember 中编写一些代码,当密钥不存在时自动添加字典,但我不需要,所以我没有添加它。

      【讨论】:

        【解决方案4】:

        很简单

        扩展

        public static class ObjectExtension
        {
            public static ExpandoObject ToExpando(this object source)
            {
                IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(source);
        
                IDictionary<string, object> expando = new ExpandoObject();
        
                foreach (var item in anonymousDictionary)
                    expando.Add(item);
        
                return (ExpandoObject)expando;
            }
        }
        

        客户操作

            public IActionResult Client(string username)
            {
                var client = HttpContext.Items["profile"] as Client;
        
                var model = new
                {
                    client.Id,
                    client.Name,
                    client.Surname,
                    client.Username,
                    client.Photo,
                    CoverPhoto = new {
                       client.CoverPhoto.Source,
                       client.CoverPhoto.X
                    }.ToExpando(),
                }.ToExpando();
        
                return View(model);
            }
        

        Client.cshtml

        <img id="cover-photo" src="@Model.CoverPhoto.Source" />
        

        【讨论】:

          猜你喜欢
          • 2011-06-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-04-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多