Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DataVisitorBase.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.Reflection;
7 
8 namespace SiliconStudio.Core.Reflection
9 {
10  /// <summary>
11  /// A visitor for serializable data (binary, yaml and editor).
12  /// </summary>
13  public abstract class DataVisitorBase : IDataVisitor
14  {
15  private readonly HashSet<object> visitedObjects = new HashSet<object>(ReferenceEqualityComparer<object>.Default);
16  private readonly Dictionary<Type, IDataCustomVisitor> mapTypeToCustomVisitors = new Dictionary<Type, IDataCustomVisitor>();
17  private VisitorContext context;
18 
19  /// <summary>
20  /// Initializes a new instance of the <see cref="DataVisitorBase"/> class.
21  /// </summary>
22  /// <param name="attributeRegistry">The attribute registry.</param>
23  protected DataVisitorBase(IAttributeRegistry attributeRegistry) : this(new TypeDescriptorFactory(attributeRegistry))
24  {
25  }
26 
27  /// <summary>
28  /// Initializes a new instance of the <see cref="DataVisitorBase"/> class.
29  /// </summary>
30  protected DataVisitorBase()
31  : this(new TypeDescriptorFactory(new AttributeRegistry()))
32  {
33  }
34 
35  /// <summary>
36  /// Initializes a new instance of the <see cref="DataVisitorBase"/> class.
37  /// </summary>
38  /// <param name="typeDescriptorFactory">The type descriptor factory.</param>
39  /// <exception cref="System.ArgumentNullException">typeDescriptorFactory</exception>
40  protected DataVisitorBase(ITypeDescriptorFactory typeDescriptorFactory)
41  {
42  if (typeDescriptorFactory == null) throw new ArgumentNullException("typeDescriptorFactory");
43  TypeDescriptorFactory = typeDescriptorFactory;
44  CustomVisitors = new List<IDataCustomVisitor>();
45  context.DescriptorFactory = TypeDescriptorFactory;
46  context.Visitor = this;
47  CurrentPath = new MemberPath(16);
48  }
49 
50  /// <summary>
51  /// Gets the type descriptor factory.
52  /// </summary>
53  /// <value>The type descriptor factory.</value>
54  public ITypeDescriptorFactory TypeDescriptorFactory { get; private set; }
55 
56  /// <summary>
57  /// Gets or sets the custom visitors.
58  /// </summary>
59  /// <value>The custom visitors.</value>
60  public List<IDataCustomVisitor> CustomVisitors { get; private set; }
61 
62  /// <summary>
63  /// Gets the current member path being visited.
64  /// </summary>
65  /// <value>The current path.</value>
66  protected MemberPath CurrentPath { get; private set; }
67 
68  /// <summary>
69  /// Gets the attribute registry.
70  /// </summary>
71  /// <value>The attribute registry.</value>
73  {
74  get
75  {
77  }
78  }
79 
80  /// <summary>
81  /// Resets this instance (clears the cache of visited objects).
82  /// </summary>
83  public virtual void Reset()
84  {
85  visitedObjects.Clear();
86  }
87 
88  /// <summary>
89  /// Visits the specified object.
90  /// </summary>
91  /// <param name="obj">The object.</param>
92  public void Visit(object obj)
93  {
94  Visit(obj, null);
95  }
96 
97  /// <summary>
98  /// Visits the specified object.
99  /// </summary>
100  /// <param name="obj">The object.</param>
101  /// <param name="descriptor">The descriptor.</param>
102  /// <exception cref="System.ArgumentNullException">
103  /// obj
104  /// or
105  /// descriptor
106  /// </exception>
107  /// <exception cref="System.ArgumentException">Descriptor [{0}] type doesn't correspond to object type [{1}].ToFormat(descriptor.Type, obj.GetType())</exception>
108  protected void Visit(object obj, ITypeDescriptor descriptor)
109  {
110  if (obj == null)
111  {
112  VisitNull();
113  return;
114  }
115 
116  var objectType = obj.GetType();
117  if (descriptor == null || descriptor.Type != objectType)
118  {
119  descriptor = TypeDescriptorFactory.Find(objectType);
120  }
121 
122  if (descriptor is NullableDescriptor)
123  {
124  descriptor = TypeDescriptorFactory.Find(((NullableDescriptor)descriptor).UnderlyingType);
125  }
126 
127  context.Instance = obj;
128  context.Descriptor = (ObjectDescriptor)descriptor;
129 
130  switch (descriptor.Category)
131  {
132  case DescriptorCategory.Primitive:
133  VisitPrimitive(obj, (PrimitiveDescriptor)descriptor);
134  break;
135  default:
136  if (CanVisit(obj))
137  {
138  IDataCustomVisitor customVisitor;
139  if (!mapTypeToCustomVisitors.TryGetValue(objectType, out customVisitor) && CustomVisitors.Count > 0)
140  {
141  for (int i = CustomVisitors.Count - 1; i >= 0; i--)
142  {
143  var dataCustomVisitor = CustomVisitors[i];
144  if (dataCustomVisitor.CanVisit(objectType))
145  {
146  customVisitor = dataCustomVisitor;
147  mapTypeToCustomVisitors.Add(objectType, dataCustomVisitor);
148  break;
149  }
150  }
151  }
152 
153  if (customVisitor != null)
154  {
155  customVisitor.Visit(ref context);
156  }
157  else
158  {
159  VisitObject(obj, context.Descriptor, true);
160  }
161  }
162  break;
163  }
164  }
165 
166  public virtual void VisitNull()
167  {
168  }
169 
170  public virtual void VisitPrimitive(object primitive, PrimitiveDescriptor descriptor)
171  {
172  }
173 
174  public virtual void VisitObject(object obj, ObjectDescriptor descriptor, bool visitMembers)
175  {
176  if (!obj.GetType().IsArray && visitMembers)
177  {
178  foreach (var member in descriptor.Members)
179  {
180  CurrentPath.Push(member);
181  VisitObjectMember(obj, descriptor, member, member.Get(obj));
182  CurrentPath.Pop();
183  }
184  }
185 
186  switch (descriptor.Category)
187  {
188  case DescriptorCategory.Array:
189  VisitArray((Array)obj, (ArrayDescriptor)descriptor);
190  break;
191  case DescriptorCategory.Collection:
192  VisitCollection((IEnumerable)obj, (CollectionDescriptor)descriptor);
193  break;
194  case DescriptorCategory.Dictionary:
195  VisitDictionary(obj, (DictionaryDescriptor)descriptor);
196  break;
197  }
198  }
199 
200  public virtual void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value)
201  {
202  Visit(value, member.TypeDescriptor);
203  }
204 
205  public virtual void VisitArray(Array array, ArrayDescriptor descriptor)
206  {
207  for (int i = 0; i < array.Length; i++)
208  {
209  var value = array.GetValue(i);
210  CurrentPath.Push(descriptor, i);
211  VisitArrayItem(array, descriptor, i, value, value == null ? null : TypeDescriptorFactory.Find(value.GetType()));
212  CurrentPath.Pop();
213  }
214  }
215 
216  public virtual void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
217  {
218  Visit(item, itemDescriptor);
219  }
220 
221  public virtual void VisitCollection(IEnumerable collection, CollectionDescriptor descriptor)
222  {
223  int i = 0;
224  foreach (var item in collection)
225  {
226  CurrentPath.Push(descriptor, i);
227  VisitCollectionItem(collection, descriptor, i, item, item == null ? null : TypeDescriptorFactory.Find(item.GetType()));
228  CurrentPath.Pop();
229  i++;
230  }
231  }
232 
233  public virtual void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
234  {
235  Visit(item, itemDescriptor);
236  }
237 
238  public virtual void VisitDictionary(object dictionary, DictionaryDescriptor descriptor)
239  {
240  foreach (var keyValue in descriptor.GetEnumerator(dictionary))
241  {
242  var key = keyValue.Key;
243  var keyDescriptor = keyValue.Key == null ? null : TypeDescriptorFactory.Find(keyValue.Key.GetType());
244  var value = keyValue.Value;
245  var valueDescriptor = keyValue.Value == null ? null : TypeDescriptorFactory.Find(keyValue.Value.GetType());
246 
247  CurrentPath.Push(descriptor, key);
248  VisitDictionaryKeyValue(dictionary, descriptor, key, keyDescriptor, value, valueDescriptor);
249  CurrentPath.Pop();
250  }
251  }
252 
253  public virtual void VisitDictionaryKeyValue(object dictionary, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor)
254  {
255  Visit(key, keyDescriptor);
256  Visit(value, valueDescriptor);
257  }
258 
259  private bool CanVisit(object obj)
260  {
261  // Always visit valuetypes
262  if (obj.GetType().GetTypeInfo().IsValueType)
263  {
264  return true;
265  }
266 
267  if (visitedObjects.Contains(obj))
268  {
269  return false;
270  }
271  visitedObjects.Add(obj);
272  return true;
273  }
274  }
275 }
Provides a descriptor for a System.Collections.ICollection.
virtual void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
Visits an array item.
A default implementation for the ITypeDescriptorFactory.
DescriptorCategory Category
Gets the category of this descriptor.
DataVisitorBase(IAttributeRegistry attributeRegistry)
Initializes a new instance of the DataVisitorBase class.
virtual void VisitArray(Array array, ArrayDescriptor descriptor)
Visits an array.
Default implementation of a ITypeDescriptor.
virtual void VisitDictionaryKeyValue(object dictionary, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor)
Visits a dictionary key-value.
Type Type
Gets the type described by this instance.
void Visit(object obj)
Visits the specified object.
A visitor for serializable data (binary, yaml and editor).
Interface for visiting serializable data (binary, yaml and editor).
Definition: IDataVisitor.cs:11
virtual void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
Visits a collection item.
Provides a descriptor for a System.Collections.IDictionary.
Describes a descriptor for a primitive (bool, char, sbyte, byte, int, uint, long, ulong...
Describes a descriptor for a nullable type Nullable{T}.
virtual void VisitPrimitive(object primitive, PrimitiveDescriptor descriptor)
Visits a primitive (int, float, string...etc.)
virtual void VisitObject(object obj, ObjectDescriptor descriptor, bool visitMembers)
Visits an object (either a class or a struct)
Allows to get/set a property/field value on a deeply nested object instance (supporting members...
Definition: MemberPath.cs:14
ITypeDescriptor Find(Type type)
Tries to create an instance of a ITypeDescriptor from the type. Return null if this factory is not ha...
DataVisitorBase(ITypeDescriptorFactory typeDescriptorFactory)
Initializes a new instance of the DataVisitorBase class.
virtual void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value)
Visits an object member.
A custom visitor used by DataVisitorBase.
IEnumerable< IMemberDescriptor > Members
Provides access members of a type.
SiliconStudio.Core.Reflection.AttributeRegistry AttributeRegistry
virtual void VisitDictionary(object dictionary, DictionaryDescriptor descriptor)
Visits a dictionary.
virtual void Reset()
Resets this instance (clears the cache of visited objects).
virtual void VisitCollection(IEnumerable collection, CollectionDescriptor descriptor)
Visits a collection.
A factory to create an instance of a ITypeDescriptor
DataVisitorBase()
Initializes a new instance of the DataVisitorBase class.
A default implementation for IAttributeRegistry. This implementation allows to retrieve default attri...
void Visit(object obj, ITypeDescriptor descriptor)
Visits the specified object.