2014-10-17 23 views
0

的问题

使用C#,我需要遍历已被强制转换为ExpandoObjectXML一个对象,并用新的值来代替“价格”属性。在C#中,如何在递归遍历ExpandoObject的同时更改Key-Value-Property的值?

该对象是非结构化的,并且有许多嵌套节点层(实际上是嵌套的ExpandoObjects)。更具体地讲,层次结构可能看起来像这样:

产品=>价格,数量,配件

每个配件可以有一个价格和数量,并可能本身具有的配件,这就是为什么我需要递归。

我有什么到目前为止

public ExpandoObject UpdatePricing(ExpandoObject exp) 
    { 
     //Is there a price property? 
     var hasPrice = exp.Any(a => a.Key == "price"); 
     if (hasPrice) 
     { 
      //update price here 
      exp.price = 0; //Some other price 
     } 

     //Now loop through the whole object. If any of the properties contain an expando, then call this method again 
     foreach (var kvp in exp) 
     { 
      if (kvp.Value is ExpandoObject) 
      { 
       //THIS CODE IS NO GOOD BECAUSE kvp.Value has no setter!! 
       kvp.Value = UpdatePricing(kvp.Value); 
      } 
     } 

     return exp; 
    } 

我遇到的问题是,kvp.Value没有二传手,所以我不能递归运行这个方法。

任何建议表示赞赏。谢谢!

+0

我会重新组织树中的结构。 – BlueTrin 2014-10-17 23:24:13

+0

你有什么特别的错误?当你运行它时,会发生什么异常? – Haney 2014-10-17 23:25:59

+0

返回kvp的意义何在?为什么不只是用void方法递归处理呢?或者避免将结果分配给kvp.Value。 – codenheim 2014-10-17 23:26:40

回答

1

由于ExpandoObject implements IDictionary<string, Object>事情可以变得更容易一些。我们也可以将退货类型更改为void,因为我们不需要重新分配结果。

void UpdatePrice(ExpandoObject expando, decimal price) 
{ 
    var map = (IDictionary<string, Object>)expando; 
    if (map.ContainsKey("price")) 
     map["price"] = price; 
    foreach (var value in map.Values) 
    { 
     if (value is ExpandoObject) 
      UpdatePrice((ExpandoObject)value, price); 
    } 
} 
1

我对ExpandoObject了解不多。但是,像大多数字典实现一样,我假设一般情况下,如果您希望将键值对更新为具有不同的值,则需要查看字典界面。

请注意,您(可能)在枚举其内容时将不被允许修改字典。所以你需要建立一个要更新的元素列表,并在一个单独的操作中完成。

例如:

List<string> keysToUpdate = new List<string>(); 

foreach (var kvp in exp) 
{ 
    if (kvp.Value is ExpandoObject) 
    { 
     keysToUpdate.Add(kvp.Key); 
    } 
} 

foreach (string key in keysToUpdate) 
{ 
    exp[key] = UpdatePricing(exp[key]); 
} 

你也可以保持整个KeyValuePair值列表,以避免值的第二检索,但我猜这不是在这里一个重要的优化。

1

我只是跑在这一个小测试,并能够得到它具有的expando是动态的工作:

public static ExpandoObject DoWork(ExpandoObject obj) 
    { 
     dynamic expando = obj; 

     //update price 
     if (obj.Any(c => c.Key == "price")) 
      expando.price = 354.11D; 

     foreach (var item in expando) 
     { 
      if (item.Value is ExpandoObject) 
      { 
       //call recursively 
       DoWork(item.Value); 
      } 
     } 
     return expando; 
    } 

它elimitates类型安全,但它看起来像你没有这样的奢侈反正,动态是与根据MSDN其实expandos将交互的最佳方法:

“在C#中,以启用ExpandoObject 类的实例后期绑定,你必须使用动态关键字的详细信息,请参阅 使用类型动态(C#编程指南)“。

这意味着,如果你不使用dynamic关键字,您在CLR运行Expando的,而不是具有像不能够设定值一些奇怪的后果DLR的。希望这有助于。