IDictionaryExtensions.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace Topten.JsonKit
  7. {
  8. /// <summary>
  9. /// Helper extensions for navigating dictionaries of string/object
  10. /// </summary>
  11. public static class IDictionaryExtensions
  12. {
  13. /// <summary>
  14. /// Navigates a string/object dictionary following a path
  15. /// </summary>
  16. /// <param name="This">The root dictionary</param>
  17. /// <param name="Path">The path to follow</param>
  18. /// <param name="create">Whether to create nodes as walking the path</param>
  19. /// <param name="leafCallback">A callback invoked for each lead node. Return false to stop walk</param>
  20. /// <returns>Result of last leafCallback, or false if key not found and create parameter is false</returns>
  21. public static bool WalkPath(
  22. this IDictionary<string, object> This,
  23. string Path,
  24. bool create,
  25. Func<IDictionary<string,object>,string, bool> leafCallback
  26. )
  27. {
  28. // Walk the path
  29. var parts = Path.Split('.');
  30. for (int i = 0; i < parts.Length-1; i++)
  31. {
  32. object val;
  33. if (!This.TryGetValue(parts[i], out val))
  34. {
  35. if (!create)
  36. return false;
  37. val = new Dictionary<string, object>();
  38. This[parts[i]] = val;
  39. }
  40. This = (IDictionary<string,object>)val;
  41. }
  42. // Process the leaf
  43. return leafCallback(This, parts[parts.Length-1]);
  44. }
  45. /// <summary>
  46. /// Check if a path exists in an string/object dictionary heirarchy
  47. /// </summary>
  48. /// <param name="This">The root dictionary</param>
  49. /// <param name="Path">The path to follow</param>
  50. /// <returns>True if the path exists</returns>
  51. public static bool PathExists(this IDictionary<string, object> This, string Path)
  52. {
  53. return This.WalkPath(Path, false, (dict, key) => dict.ContainsKey(key));
  54. }
  55. /// <summary>
  56. /// Gets the object at the specified path in an string/object dictionary heirarchy
  57. /// </summary>
  58. /// <param name="This">The root dictionary</param>
  59. /// <param name="type">The expected returned object type</param>
  60. /// <param name="Path">The path to follow</param>
  61. /// <param name="def">The default value if the value isn't found</param>
  62. /// <returns></returns>
  63. public static object GetPath(this IDictionary<string, object> This, Type type, string Path, object def)
  64. {
  65. This.WalkPath(Path, false, (dict, key) =>
  66. {
  67. object val;
  68. if (dict.TryGetValue(key, out val))
  69. {
  70. if (val == null)
  71. def = val;
  72. else if (type.IsAssignableFrom(val.GetType()))
  73. def = val;
  74. else
  75. def = Json.Reparse(type, val);
  76. }
  77. return true;
  78. });
  79. return def;
  80. }
  81. /// <summary>
  82. /// Gets an object of specified type at a path location in a string/object dictionaryt
  83. /// </summary>
  84. /// <typeparam name="T">The returned object type</typeparam>
  85. /// <param name="This">The root dictionary</param>
  86. /// <param name="Path">The path of the object to return</param>
  87. /// <returns>The object instance</returns>
  88. public static T GetObjectAtPath<T>(this IDictionary<string, object> This, string Path) where T:class,new()
  89. {
  90. T retVal = null;
  91. This.WalkPath(Path, true, (dict, key) =>
  92. {
  93. object val;
  94. dict.TryGetValue(key, out val);
  95. retVal = val as T;
  96. if (retVal == null)
  97. {
  98. retVal = val == null ? new T() : Json.Reparse<T>(val);
  99. dict[key] = retVal;
  100. }
  101. return true;
  102. });
  103. return retVal;
  104. }
  105. /// <summary>
  106. /// Get a value at a path in a string/object dictionary heirarchy
  107. /// </summary>
  108. /// <typeparam name="T">The type of object to be returned</typeparam>
  109. /// <param name="This">The root dictionary</param>
  110. /// <param name="Path">The path of the entry to find</param>
  111. /// <param name="def">The default value to return if not found</param>
  112. /// <returns>The located value, or the default value if not found</returns>
  113. public static T GetPath<T>(this IDictionary<string, object> This, string Path, T def = default(T))
  114. {
  115. return (T)This.GetPath(typeof(T), Path, def);
  116. }
  117. /// <summary>
  118. /// Set a value in a string/object dictionary heirarchy
  119. /// </summary>
  120. /// <param name="This">The root dictionary</param>
  121. /// <param name="Path">The path of the value to set</param>
  122. /// <param name="value">The value to set</param>
  123. public static void SetPath(this IDictionary<string, object> This, string Path, object value)
  124. {
  125. This.WalkPath(Path, true, (dict, key) => { dict[key] = value; return true; });
  126. }
  127. }
  128. }