Guest User

Untitled

a guest
Apr 25th, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.00 KB | None | 0 0
  1. class TypedKey<T>
  2. {
  3. public string Name { get; private set; }
  4.  
  5. public TypedKey(string name)
  6. {
  7. Name = name;
  8. }
  9. }
  10.  
  11. static class DictionaryExtensions
  12. {
  13. public static T Get<T>(this IDictionary<string, object> dictionary, TypedKey<T> key)
  14. {
  15. return (T)dictionary[key.Name];
  16. }
  17.  
  18. public static void Set<T>(this IDictionary<string, object> dictionary, TypedKey<T> key, T value)
  19. {
  20. dictionary[key.Name] = value;
  21. }
  22. }
  23.  
  24. private static readonly TypedKey<int> AgeKey = new TypedKey<int>("age");
  25.  
  26.  
  27. dictionary.Get(AgeKey) > 18
  28. dictionary.Set(AgeKey, age)
  29.  
  30. static class DictionaryExtensions
  31. {
  32. public static T Get<T>(this IDictionary<string, object> dictionary, string key)
  33. {
  34. return (T)dictionary[key];
  35. }
  36.  
  37. public static bool TryGet<T>(this IDictionary<string, object> dictionary,
  38. string key, out T value)
  39. {
  40. object result;
  41. if (dictionary.TryGetValue(key, out result) && result is T) {
  42. value = (T)result;
  43. return true;
  44. }
  45. value = default(T);
  46. return false;
  47. }
  48.  
  49. public static void Set(this IDictionary<string, object> dictionary,
  50. string key, object value)
  51. {
  52. dictionary[key] = value;
  53. }
  54. }
  55.  
  56. int age = 20;
  57. dictionary.Set("age", age);
  58.  
  59. // ...
  60.  
  61. age = dictionary.Get<int>("age");
  62.  
  63. // or the safe way
  64. if (dictionary.TryGet("age", out age)) {
  65. Console.WriteLine("The age is {0}", age);
  66. } else {
  67. Console.WriteLine("Age not found or of wrong type");
  68. }
  69.  
  70. public class Property<T>
  71. {
  72. Dictionary<object, object> _dict;
  73.  
  74. public Property (Dictionary<object, object> dict)
  75. {
  76. _dict = dict;
  77. }
  78.  
  79. public T Value {
  80. get { return (T)_dict[this]; }
  81. set { _dict[this] = value; }
  82. }
  83. }
  84.  
  85. private static readonly Dictionary<object, object> _properties =
  86. new Dictionary<object, object>();
  87. private static readonly Property<int> _age = new Property<int>(_properties);
  88.  
  89. ...
  90.  
  91. _age.Value > 18
  92. _age.Value = age
  93.  
  94. public interface ITypedKey<T>
  95. {
  96. string Name { get; }
  97. }
  98.  
  99. public class TypedKey<T> : ITypedKey<T>
  100. {
  101. private readonly string name;
  102.  
  103. public TypedKey(string name)
  104. {
  105. if (name == null)
  106. {
  107. throw new ArgumentNullException("name");
  108. }
  109.  
  110. this.name = name;
  111. }
  112.  
  113. public string Name
  114. {
  115. get
  116. {
  117. return this.name;
  118. }
  119. }
  120. }
  121.  
  122. public interface IPropertyBag
  123. {
  124. T Get<T>(ITypedKey<T> key);
  125.  
  126. void Set<T>(ITypedKey<T> key, T value);
  127.  
  128. void Remove<T>(ITypedKey<T> key);
  129. }
  130.  
  131. public class PropertyBag : IPropertyBag
  132. {
  133. private readonly IDictionary<string, object> bag;
  134.  
  135. public PropertyBag()
  136. {
  137. this.bag = new Dictionary<string, object>();
  138. }
  139.  
  140. public PropertyBag(IDictionary dict)
  141. {
  142. if (dict == null)
  143. {
  144. throw new ArgumentNullException("dict");
  145. }
  146.  
  147. this.bag = new Dictionary<string, object>(dict.Count);
  148. foreach (DictionaryEntry kvp in dict)
  149. {
  150. this.bag.Add(new KeyValuePair<string, object>(kvp.Key as string, kvp.Value));
  151. }
  152. }
  153.  
  154. public T Get<T>(ITypedKey<T> key)
  155. {
  156. if (key == null)
  157. {
  158. throw new ArgumentNullException("key");
  159. }
  160.  
  161. return (T)this.bag[key.Name];
  162. }
  163.  
  164. public void Set<T>(ITypedKey<T> key, T value)
  165. {
  166. if (key == null)
  167. {
  168. throw new ArgumentNullException("key");
  169. }
  170.  
  171. this.bag[key.Name] = value;
  172. }
  173.  
  174. public void Remove<T>(ITypedKey<T> key)
  175. {
  176. if (key == null)
  177. {
  178. throw new ArgumentNullException("key");
  179. }
  180.  
  181. this.bag.Remove(key.Name);
  182. }
  183. }
  184.  
  185. private static readonly TypedKey<int> AgeKey = new TypedKey<int>("age");
  186. private static readonly TypedKey<string> BadAgeKey = new TypedKey<string>("age");
  187. dictionary.Set(BadAgeKey, “foo”);
  188. ...
  189. // this would throw
  190. dictionary.Get(AgeKey);
  191.  
  192. public class TypeSafeKey<T> { }
  193.  
  194. public class TypeSafeKeyValuePairBag
  195. {
  196. public T GetItemOrDefault<TKey, T>(T defaultValue = default(T)) where TKey : TypeSafeKey<T>
  197. => TryGet(typeof(TKey), out T result) ? result : defaultValue;
  198.  
  199. public T GetItemOrDefault<T>(TypeSafeKey<T> key, T defaultValue = default(T))
  200. => TryGet(key?.GetType() ?? throw new ArgumentNullException(nameof(key)), out T result) ? result : defaultValue;
  201.  
  202. public void SetItem<TKey, T>(T value) where TKey : TypeSafeKey<T>
  203. => m_values[typeof(TKey)] = value;
  204.  
  205. public void SetItem<T>(TypeSafeKey<T> key, T value)
  206. => m_values[key?.GetType() ?? throw new ArgumentNullException(nameof(key))] = value;
  207.  
  208. public T GetItem<TKey, T>() where TKey : TypeSafeKey<T>
  209. => Get<T>(typeof(TKey));
  210.  
  211. public T GetItem<T>(TypeSafeKey<T> key)
  212. => Get<T>(key?.GetType() ?? throw new ArgumentNullException(nameof(key)));
  213.  
  214. private bool TryGet<T>(Type type, out T value)
  215. {
  216. if (m_values.TryGetValue(type, out object obj))
  217. {
  218. value = (T)obj;
  219. return true;
  220. }
  221.  
  222. value = default(T);
  223. return false;
  224. }
  225.  
  226. private T Get<T>(Type type)
  227. => TryGet(type, out T result) ? result : throw new KeyNotFoundException($"Key {type.FullName} not found");
  228.  
  229. private Dictionary<Type, object> m_values = new Dictionary<Type, object>();
  230. }
  231.  
  232. // You need to declare a Type for each key that you want to use, all though the types can defined anywhere
  233. // They don't need to be known to the assembly where TypeSafeKeyValuePairBag is defined, but they do need to
  234. // be known to the any code that is setting or getting any given key. So even though the declaration of
  235. // these class could be spread throughout the source tree, since each is a type they are forced to be unique
  236. public class KeyHight : TypeSafeKey<int> { }
  237. public class KeyWidth : TypeSafeKey<int> { }
  238. public class KeyName : TypeSafeKey<string> { }
  239.  
  240. // A static class, with static public members would reduce the number of instances of objects that needed to be created for repeated reads/writes.
  241. // You would need to create these in a lazy fashion if you had many of them. And since only their type matters, you don’t need to worry about locking, since two different instances of the same Type would function as the same key.
  242. public static class Keys
  243. {
  244. public static KeyHight KeyHight { get; } = new KeyHight();
  245. public static KeyWidth KeyWidth { get; } = new KeyWidth();
  246. public static KeyName KeyName { get; } = new KeyName();
  247. }
  248.  
  249. ...
  250.  
  251. TypeSafeKeyValuePairBag bag = new TypeSafeKeyValuePairBag();
  252.  
  253. // Accessing hard coded keys
  254. //Using Generic Type Parameters: The compiler can't infer the value Type from the Key Type, which means listing them both
  255. bag.SetItem<KeyHight, int>(5);
  256. //Passing the key as a parameter
  257. bag.SetItem(Keys.KeyWidth, 10);
  258. bag.SetItem(Keys.KeyName, "foo");
  259.  
  260. // Selecting which keys to access at run time
  261. int value = 1;
  262. foreach(var key in new TypeSafeKey<int>[] { Keys.KeyHight, Keys.KeyWidth })
  263. {
  264. value *= bag.GetItem(key);
  265. }
  266.  
  267. Console.WriteLine($"{bag.GetItem<KeyName, string>()}'s area is {value}");
  268.  
  269. private bool TryGet<T>(Type type, out T value)
  270. {
  271. if (m_values.TryGetValue(type, out object obj))
  272. {
  273. value = (T)obj;
  274. return true;
  275. }
  276.  
  277. Type baseType = type.BaseType;
  278. if (baseType != typeof(TypeSafeKey<T>))
  279. {
  280. return TryGet(baseType, out value);
  281. }
  282.  
  283. value = default(T);
  284. return false;
  285. }
  286.  
  287. public class KeyLevel0Value : TypeSafeKey<int> { }
  288. public class KeyLevelA1Value : KeyLevel0Value { }
  289. public class KeyLevelA2Value : KeyLevelA1Value { }
  290. public class KeyLevelB1Value : KeyLevel0Value { }
  291. public class KeyLevelB2Value : KeyLevelB1Value { }
  292.  
  293. ...
  294.  
  295. bag.SetItem<KeyLevelA1Value, int>(5);
  296. // This will first check the value for LevelA2. After not finding it, it will check LevelA2, and that value will be returned
  297. Console.WriteLine(bag.GetItem<KeyLevelA2Value, int>());
  298. // This will first check the value for LevelB2, LevelB1, and finally Level0, and since none are set it will return default
  299. Console.WriteLine(bag.GetItemOrDefault<KeyLevelB2Value, int>());
Add Comment
Please, Sign In to add comment