2014-10-17 72 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的。希望這有助於。