Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DictionaryDescriptor.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Reflection;
8 
9 namespace SiliconStudio.Core.Reflection
10 {
11  /// <summary>
12  /// Provides a descriptor for a <see cref="System.Collections.IDictionary"/>.
13  /// </summary>
15  {
16  private static readonly List<string> ListOfMembersToRemove = new List<string> {"Comparer", "Keys", "Values", "Capacity" };
17 
18  private readonly Type keyType;
19  private readonly Type valueType;
20  private readonly MethodInfo getEnumeratorGeneric;
21  private readonly PropertyInfo getKeysMethod;
22  private readonly PropertyInfo getValuesMethod;
23  private readonly PropertyInfo indexerProperty;
24  private readonly MethodInfo indexerSetter;
25  private readonly MethodInfo removeMethod;
26  private readonly MethodInfo containsKeyMethod;
27 
28  /// <summary>
29  /// Initializes a new instance of the <see cref="DictionaryDescriptor" /> class.
30  /// </summary>
31  /// <param name="factory">The factory.</param>
32  /// <param name="type">The type.</param>
33  /// <exception cref="System.ArgumentException">Expecting a type inheriting from System.Collections.IDictionary;type</exception>
34  public DictionaryDescriptor(ITypeDescriptorFactory factory, Type type)
35  : base(factory, type)
36  {
37  if (!IsDictionary(type))
38  throw new ArgumentException(@"Expecting a type inheriting from System.Collections.IDictionary", "type");
39 
40  Category = DescriptorCategory.Dictionary;
41 
42  // extract Key, Value types from IDictionary<??, ??>
43  var interfaceType = type.GetInterface(typeof(IDictionary<,>));
44  if (interfaceType != null)
45  {
46  keyType = interfaceType.GetGenericArguments()[0];
47  valueType = interfaceType.GetGenericArguments()[1];
48  IsGenericDictionary = true;
49  getEnumeratorGeneric = typeof(DictionaryDescriptor).GetMethod("GetGenericEnumerable").MakeGenericMethod(keyType, valueType);
50  containsKeyMethod = type.GetMethod("ContainsKey", new[] { keyType });
51  }
52  else
53  {
54  keyType = typeof(object);
55  valueType = typeof(object);
56  containsKeyMethod = type.GetMethod("Contains", new[] { keyType });
57  }
58 
59  getKeysMethod = type.GetProperty("Keys");
60  getValuesMethod = type.GetProperty("Values");
61  indexerProperty = type.GetProperty("Item", valueType, new[] { keyType });
62  indexerSetter = indexerProperty.SetMethod;
63  removeMethod = type.GetMethod("Remove", new[] { keyType });
64  }
65 
66  public override void Initialize()
67  {
68  base.Initialize();
69 
70  // Only Keys and Values
71  IsPureDictionary = Count == 0;
72  }
73 
74  /// <summary>
75  /// Gets a value indicating whether this instance is generic dictionary.
76  /// </summary>
77  /// <value><c>true</c> if this instance is generic dictionary; otherwise, <c>false</c>.</value>
78  public bool IsGenericDictionary { get; private set; }
79 
80  /// <summary>
81  /// Gets the type of the key.
82  /// </summary>
83  /// <value>The type of the key.</value>
84  public Type KeyType
85  {
86  get
87  {
88  return keyType;
89  }
90  }
91 
92  /// <summary>
93  /// Gets the type of the value.
94  /// </summary>
95  /// <value>The type of the value.</value>
96  public Type ValueType
97  {
98  get
99  {
100  return valueType;
101  }
102  }
103 
104  /// <summary>
105  /// Gets or sets a value indicating whether this instance is pure dictionary.
106  /// </summary>
107  /// <value><c>true</c> if this instance is pure dictionary; otherwise, <c>false</c>.</value>
108  public bool IsPureDictionary { get; private set; }
109 
110  /// <summary>
111  /// Determines whether the value passed is readonly.
112  /// </summary>
113  /// <param name="thisObject">The this object.</param>
114  /// <returns><c>true</c> if [is read only] [the specified this object]; otherwise, <c>false</c>.</returns>
115  public bool IsReadOnly(object thisObject)
116  {
117  return ((IDictionary)thisObject).IsReadOnly;
118  }
119 
120  /// <summary>
121  /// Gets a generic enumerator for a dictionary.
122  /// </summary>
123  /// <param name="dictionary">The dictionary.</param>
124  /// <returns>A generic enumerator.</returns>
125  /// <exception cref="System.ArgumentNullException">dictionary</exception>
126  /// <exception cref="System.NotSupportedException">Key value-pair [{0}] is not supported for IDictionary. Only DictionaryEntry.ToFormat(keyValueObject)</exception>
128  {
129  if (dictionary == null) throw new ArgumentNullException("dictionary");
130  if (IsGenericDictionary)
131  {
132  foreach (var item in (IEnumerable<KeyValuePair<object, object>>)getEnumeratorGeneric.Invoke(null, new[] {dictionary}))
133  {
134  yield return item;
135  }
136  }
137  else
138  {
139  var simpleDictionary = (IDictionary)dictionary;
140  foreach (var keyValueObject in simpleDictionary)
141  {
142  if (!(keyValueObject is DictionaryEntry))
143  {
144  throw new NotSupportedException("Key value-pair type [{0}] is not supported for IDictionary. Only DictionaryEntry".ToFormat(keyValueObject));
145  }
146  var entry = (DictionaryEntry)keyValueObject;
147  yield return new KeyValuePair<object, object>(entry.Key, entry.Value);
148  }
149  }
150  }
151 
152  /// <summary>
153  /// Adds a a key-value to a dictionary.
154  /// </summary>
155  /// <param name="dictionary">The dictionary.</param>
156  /// <param name="key">The key.</param>
157  /// <param name="value">The value.</param>
158  /// <exception cref="System.InvalidOperationException">No Add() method found on dictionary [{0}].ToFormat(Type)</exception>
159  public void SetValue(object dictionary, object key, object value)
160  {
161  if (dictionary == null) throw new ArgumentNullException("dictionary");
162  var simpleDictionary = dictionary as IDictionary;
163  if (simpleDictionary != null)
164  {
165  simpleDictionary[key] = value;
166  }
167  else
168  {
169  // Only throw an exception if the addMethod is not accessible when adding to a dictionary
170  if (indexerSetter == null)
171  {
172  throw new InvalidOperationException("No indexer this[key] method found on dictionary [{0}]".ToFormat(Type));
173  }
174  indexerSetter.Invoke(dictionary, new[] { key, value });
175  }
176  }
177 
178  /// <summary>
179  /// Remove a key-value from a dictionary
180  /// </summary>
181  /// <param name="dictionary">The dictionary.</param>
182  /// <param name="key">The key.</param>
183  public void Remove(object dictionary, object key)
184  {
185  if (dictionary == null) throw new ArgumentNullException("dictionary");
186  var simpleDictionary = dictionary as IDictionary;
187  if (simpleDictionary != null)
188  {
189  simpleDictionary.Remove(key);
190  }
191  else
192  {
193  // Only throw an exception if the addMethod is not accessible when adding to a dictionary
194  if (removeMethod == null)
195  {
196  throw new InvalidOperationException("No Remove() method found on dictionary [{0}]".ToFormat(Type));
197  }
198  removeMethod.Invoke(dictionary, new[] { key });
199  }
200 
201  }
202 
203  /// <summary>
204  /// Indicate whether the dictionary contains the given key
205  /// </summary>
206  /// <param name="dictionary">The dictionary.</param>
207  /// <param name="key">The key.</param>
208  public bool ContainsKey(object dictionary, object key)
209  {
210  if (dictionary == null) throw new ArgumentNullException("dictionary");
211  var simpleDictionary = dictionary as IDictionary;
212  if (simpleDictionary != null)
213  {
214  return simpleDictionary.Contains(key);
215  }
216  if (containsKeyMethod == null)
217  {
218  throw new InvalidOperationException("No ContainsKey() method found on dictionary [{0}]".ToFormat(Type));
219  }
220  return (bool)containsKeyMethod.Invoke(dictionary, new[] { key });
221  }
222 
223  /// <summary>
224  /// Returns an enumerable of the keys in the dictionary
225  /// </summary>
226  /// <param name="dictionary">The dictionary</param>
227  public IEnumerable GetKeys(object dictionary)
228  {
229  return (IEnumerable)getKeysMethod.GetValue(dictionary);
230  }
231 
232  /// <summary>
233  /// Returns an enumerable of the values in the dictionary
234  /// </summary>
235  /// <param name="dictionary">The dictionary</param>
236  public IEnumerable GetValues(object dictionary)
237  {
238  return (IEnumerable)getValuesMethod.GetValue(dictionary);
239  }
240 
241  /// <summary>
242  /// Returns the value matching the given key in the dictionary, or null if the key is not found
243  /// </summary>
244  /// <param name="dictionary">The dictionary.</param>
245  /// <param name="key">The key.</param>
246  public object GetValue(object dictionary, object key)
247  {
248  var fastDictionary = dictionary as IDictionary;
249  if (fastDictionary != null)
250  {
251  return fastDictionary[key];
252  }
253 
254  return indexerProperty.GetValue(dictionary,new [] { key });
255  }
256 
257  /// <summary>
258  /// Determines whether the specified type is a .NET dictionary.
259  /// </summary>
260  /// <param name="type">The type.</param>
261  /// <returns><c>true</c> if the specified type is dictionary; otherwise, <c>false</c>.</returns>
262  public static bool IsDictionary(Type type)
263  {
264  return typeof(IDictionary).IsAssignableFrom(type) || type.HasInterface(typeof(IDictionary<,>));
265  }
266 
267  public static IEnumerable<KeyValuePair<object, object>> GetGenericEnumerable<TKey, TValue>(IDictionary<TKey, TValue> dictionary)
268  {
269  return dictionary.Select(keyValue => new KeyValuePair<object, object>(keyValue.Key, keyValue.Value));
270  }
271 
272  protected override bool PrepareMember(MemberDescriptorBase member)
273  {
274  // Filter members
275  if (member is PropertyDescriptor && ListOfMembersToRemove.Contains(member.Name))
276  //if (member is PropertyDescriptor && (member.DeclaringType.Namespace ?? string.Empty).StartsWith(SystemCollectionsNamespace) && ListOfMembersToRemove.Contains(member.Name))
277  {
278  return false;
279  }
280 
281  return base.PrepareMember(member);
282  }
283  }
284 }
override bool PrepareMember(MemberDescriptorBase member)
void SetValue(object dictionary, object key, object value)
Adds a a key-value to a dictionary.
A IMemberDescriptor for a PropertyInfo
IEnumerable GetKeys(object dictionary)
Returns an enumerable of the keys in the dictionary
Default implementation of a ITypeDescriptor.
IEnumerable GetValues(object dictionary)
Returns an enumerable of the values in the dictionary
bool ContainsKey(object dictionary, object key)
Indicate whether the dictionary contains the given key
Provides a descriptor for a System.Collections.IDictionary.
static bool IsDictionary(Type type)
Determines whether the specified type is a .NET dictionary.
IEnumerable< KeyValuePair< object, object > > GetEnumerator(object dictionary)
Gets a generic enumerator for a dictionary.
DictionaryDescriptor(ITypeDescriptorFactory factory, Type type)
Initializes a new instance of the DictionaryDescriptor class.
void Remove(object dictionary, object key)
Remove a key-value from a dictionary
bool IsReadOnly(object thisObject)
Determines whether the value passed is readonly.
Base class for IMemberDescriptor for a MemberInfo
object GetValue(object dictionary, object key)
Returns the value matching the given key in the dictionary, or null if the key is not found ...
A factory to create an instance of a ITypeDescriptor