Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
CollectionDescriptor.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 
8 namespace SiliconStudio.Core.Reflection
9 {
10  /// <summary>
11  /// Provides a descriptor for a <see cref="System.Collections.ICollection"/>.
12  /// </summary>
14  {
15  private static readonly List<string> ListOfMembersToRemove = new List<string> { "Capacity", "Count", "IsReadOnly", "IsFixedSize", "IsSynchronized", "SyncRoot" };
16 
17  private readonly Func<object, bool> IsReadOnlyFunction;
18  private readonly Func<object, int> GetCollectionCountFunction;
19  private readonly Action<object, object> CollectionAddFunction;
20  private readonly Action<object, int, object> CollectionInsertFunction;
21  private readonly Action<object, int> CollectionRemoveAtFunction;
22  private readonly bool hasIndexerSetter;
23 
24  /// <summary>
25  /// Initializes a new instance of the <see cref="CollectionDescriptor" /> class.
26  /// </summary>
27  /// <param name="factory">The factory.</param>
28  /// <param name="type">The type.</param>
29  /// <exception cref="System.ArgumentException">Expecting a type inheriting from System.Collections.ICollection;type</exception>
30  public CollectionDescriptor(ITypeDescriptorFactory factory, Type type) : base(factory, type)
31  {
32  if (!IsCollection(type))
33  throw new ArgumentException("Expecting a type inheriting from System.Collections.ICollection", "type");
34 
35  // Gets the element type
36  var collectionType = type.GetInterface(typeof(IEnumerable<>));
37  ElementType = (collectionType != null) ? collectionType.GetGenericArguments()[0] : typeof(object);
38  Category = DescriptorCategory.Collection;
39  bool typeSupported = false;
40 
41  // implements ICollection<T>
42  Type itype = type.GetInterface(typeof(ICollection<>));
43  if (itype != null)
44  {
45  var add = itype.GetMethod("Add", new[] {ElementType});
46  CollectionAddFunction = (obj, value) => add.Invoke(obj, new[] {value});
47  var countMethod = itype.GetProperty("Count").GetGetMethod();
48  GetCollectionCountFunction = o => (int)countMethod.Invoke(o, null);
49  var isReadOnly = itype.GetProperty("IsReadOnly").GetGetMethod();
50  IsReadOnlyFunction = obj => (bool)isReadOnly.Invoke(obj, null);
51  typeSupported = true;
52  }
53  // implements IList<T>
54  itype = type.GetInterface(typeof(IList<>));
55  if (itype != null)
56  {
57  var insert = itype.GetMethod("Insert", new[] { typeof(int), ElementType });
58  CollectionInsertFunction = (obj, index, value) => insert.Invoke(obj, new[] { index, value });
59  var removeAt = itype.GetMethod("RemoveAt", new[] { typeof(int) });
60  CollectionRemoveAtFunction = (obj, index) => removeAt.Invoke(obj, new object[] { index });
61  }
62  // implements IList
63  if (!typeSupported && typeof(IList).IsAssignableFrom(type))
64  {
65  CollectionAddFunction = (obj, value) => ((IList)obj).Add(value);
66  CollectionInsertFunction = (obj, index, value) => ((IList)obj).Insert(index, value);
67  CollectionRemoveAtFunction = (obj, index) => ((IList)obj).RemoveAt(index);
68  GetCollectionCountFunction = o => ((IList)o).Count;
69  IsReadOnlyFunction = obj => ((IList)obj).IsReadOnly;
70  hasIndexerSetter = true;
71  typeSupported = true;
72  }
73 
74  if (!typeSupported)
75  {
76  throw new ArgumentException("Type [{0}] is not supported as a modifiable collection".ToFormat(type), "type");
77  }
78  }
79 
80  /// <summary>
81  /// Gets or sets the type of the element.
82  /// </summary>
83  /// <value>The type of the element.</value>
84  public Type ElementType { get; private set; }
85 
86  /// <summary>
87  /// Gets a value indicating whether this collection type has add method.
88  /// </summary>
89  /// <value><c>true</c> if this instance has add; otherwise, <c>false</c>.</value>
90  public bool HasAdd
91  {
92  get
93  {
94  return CollectionAddFunction != null;
95  }
96  }
97 
98 
99  /// <summary>
100  /// Gets a value indicating whether this collection type has insert method.
101  /// </summary>
102  /// <value><c>true</c> if this instance has insert; otherwise, <c>false</c>.</value>
103  public bool HasInsert
104  {
105  get
106  {
107  return CollectionInsertFunction != null;
108  }
109  }
110  /// <summary>
111  /// Gets a value indicating whether this collection type has RemoveAt method.
112  /// </summary>
113  /// <value><c>true</c> if this instance has RemoveAt; otherwise, <c>false</c>.</value>
114  public bool HasRemoveAt
115  {
116  get
117  {
118  return CollectionRemoveAtFunction != null;
119  }
120  }
121 
122  /// <summary>
123  /// Gets a value indicating whether this collection type has a valid indexer setter. If so, <see cref="SetValue"/> can be invoked.
124  /// </summary>
125  /// <value><c>true</c> if this instance has a valid indexer setter; otherwise, <c>false</c>.</value>
126  public bool HasIndexerSetter
127  {
128  get
129  {
130  return hasIndexerSetter;
131  }
132  }
133 
134  /// <summary>
135  /// Returns the value matching the given index in the collection.
136  /// </summary>
137  /// <param name="list">The list.</param>
138  /// <param name="index">The index.</param>
139  public object GetValue(object list, object index)
140  {
141  if (list == null) throw new ArgumentNullException("list");
142  if (!(index is int)) throw new ArgumentException("The index must be an int.");
143  return GetValue(list, (int)index);
144  }
145 
146  /// <summary>
147  /// Returns the value matching the given index in the collection.
148  /// </summary>
149  /// <param name="list">The list.</param>
150  /// <param name="index">The index.</param>
151  public object GetValue(object list, int index)
152  {
153  if (list == null) throw new ArgumentNullException("list");
154  var iList = (IList)list;
155  return iList[index];
156  }
157 
158  public void SetValue(object list, object index, object value)
159  {
160  if (list == null) throw new ArgumentNullException("list");
161  if (!(index is int)) throw new ArgumentException("The index must be an int.");
162  SetValue(list, (int)index, value);
163  }
164 
165  public void SetValue(object list, int index, object value)
166  {
167  if (list == null) throw new ArgumentNullException("list");
168  var iList = (IList)list;
169  iList[index] = value;
170  }
171 
172  /// <summary>
173  /// Add to the collections of the same type than this descriptor.
174  /// </summary>
175  /// <param name="collection">The collection.</param>
176  /// <param name="value">The value to add to this collection.</param>
177  public void Add(object collection, object value)
178  {
179  CollectionAddFunction(collection, value);
180  }
181 
182  /// <summary>
183  /// Insert to the collections of the same type than this descriptor.
184  /// </summary>
185  /// <param name="collection">The collection.</param>
186  /// <param name="index">The index of the insertion.</param>
187  /// <param name="value">The value to insert to this collection.</param>
188  public void Insert(object collection, int index, object value)
189  {
190  CollectionInsertFunction(collection, index, value);
191  }
192 
193  /// <summary>
194  /// Remove item at the given index from the collections of the same type.
195  /// </summary>
196  /// <param name="collection">The collection.</param>
197  /// <param name="index">The index of the item to remove from this collection.</param>
198  public void RemoveAt(object collection, int index)
199  {
200  CollectionRemoveAtFunction(collection, index);
201  }
202 
203  /// <summary>
204  /// Determines whether the specified collection is read only.
205  /// </summary>
206  /// <param name="collection">The collection.</param>
207  /// <returns><c>true</c> if the specified collection is read only; otherwise, <c>false</c>.</returns>
208  public bool IsReadOnly(object collection)
209  {
210  return collection == null || IsReadOnlyFunction == null || IsReadOnlyFunction(collection);
211  }
212 
213  /// <summary>
214  /// Determines the number of elements of a collection, -1 if it cannot determine the number of elements.
215  /// </summary>
216  /// <param name="collection">The collection.</param>
217  /// <returns>The number of elements of a collection, -1 if it cannot determine the number of elements.</returns>
218  public int GetCollectionCount(object collection)
219  {
220  return collection == null || GetCollectionCountFunction == null ? -1 : GetCollectionCountFunction(collection);
221  }
222 
223  /// <summary>
224  /// Determines whether the specified type is collection.
225  /// </summary>
226  /// <param name="type">The type.</param>
227  /// <returns><c>true</c> if the specified type is collection; otherwise, <c>false</c>.</returns>
228  public static bool IsCollection(Type type)
229  {
230  return !type.IsArray && (typeof(ICollection).IsAssignableFrom(type) || type.HasInterface(typeof(ICollection<>)) || typeof(IList).IsAssignableFrom(type));
231  }
232 
233  protected override bool PrepareMember(MemberDescriptorBase member)
234  {
235  // Filter members
236  if (member is PropertyDescriptor && ListOfMembersToRemove.Contains(member.Name))
237  //if (member is PropertyDescriptor && (member.DeclaringType.Namespace ?? string.Empty).StartsWith(SystemCollectionsNamespace) && ListOfMembersToRemove.Contains(member.Name))
238  {
239  return false;
240  }
241 
242  return !IsCompilerGenerated && base.PrepareMember(member);
243  }
244  }
245 }
override bool PrepareMember(MemberDescriptorBase member)
Provides a descriptor for a System.Collections.ICollection.
A IMemberDescriptor for a PropertyInfo
void Add(object collection, object value)
Add to the collections of the same type than this descriptor.
int GetCollectionCount(object collection)
Determines the number of elements of a collection, -1 if it cannot determine the number of elements...
void RemoveAt(object collection, int index)
Remove item at the given index from the collections of the same type.
Default implementation of a ITypeDescriptor.
void Insert(object collection, int index, object value)
Insert to the collections of the same type than this descriptor.
CollectionDescriptor(ITypeDescriptorFactory factory, Type type)
Initializes a new instance of the CollectionDescriptor class.
void SetValue(object list, object index, object value)
object GetValue(object list, object index)
Returns the value matching the given index in the collection.
bool IsReadOnly(object collection)
Determines whether the specified collection is read only.
void SetValue(object list, int index, object value)
object GetValue(object list, int index)
Returns the value matching the given index in the collection.
static bool IsCollection(Type type)
Determines whether the specified type is collection.
Base class for IMemberDescriptor for a MemberInfo
A factory to create an instance of a ITypeDescriptor