Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DataVisitNodeBuilder.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 SiliconStudio.Core.Reflection;
7 
8 namespace SiliconStudio.Assets.Visitors
9 {
10  /// <summary>
11  /// A visitor for producing a <see cref="DataVisitNode"/> for an object hierarchy.
12  /// </summary>
13  public sealed class DataVisitNodeBuilder : AssetVisitorBase
14  {
15  private readonly object rootInstance;
16 
17  private readonly Stack<DataVisitNode> stackItems = new Stack<DataVisitNode>();
18 
19  /// <summary>
20  /// Initializes a new instance of the <see cref="DataVisitNodeBuilder"/> class.
21  /// </summary>
22  /// <param name="typeDescriptorFactory">The type descriptor factory.</param>
23  /// <param name="rootInstance">The root instance of the object to visit.</param>
24  /// <exception cref="System.ArgumentNullException">rootInstance</exception>
25  private DataVisitNodeBuilder(ITypeDescriptorFactory typeDescriptorFactory, object rootInstance)
26  : base(typeDescriptorFactory)
27  {
28  if (rootInstance == null) throw new ArgumentNullException("rootInstance");
29  this.rootInstance = rootInstance;
30  var objectDescriptor = typeDescriptorFactory.Find(rootInstance.GetType()) as ObjectDescriptor;
31  if (objectDescriptor == null)
32  throw new ArgumentException("Expecting an object", "rootInstance");
33  stackItems.Push(new DataVisitObject(rootInstance, objectDescriptor));
34  }
35 
36  /// <summary>
37  /// Creates <see cref="DataVisitNode"/> from the specified instance.
38  /// </summary>
39  /// <param name="typeDescriptorFactory">The type descriptor factory.</param>
40  /// <param name="rootInstance">The root instance to generate diff nodes.</param>
41  /// <returns>A diff node object.</returns>
42  public static DataVisitObject Run(ITypeDescriptorFactory typeDescriptorFactory, object rootInstance)
43  {
44  if (rootInstance == null) return null;
45  return new DataVisitNodeBuilder(typeDescriptorFactory, rootInstance).Run();
46  }
47 
48  /// <summary>
49  /// Runs this instance.
50  /// </summary>
51  /// <returns>Returns the root node associated with the instance being visited.</returns>
53  {
54  Visit(rootInstance);
55  return (DataVisitObject)stackItems.Pop();
56  }
57 
58  public override void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value)
59  {
60  if (!AcceptMember(member))
61  {
62  return;
63  }
64 
65  var node = stackItems.Peek();
66  var newNode = new DataVisitMember(value, member);
67  AddMember(node, newNode);
68 
69  stackItems.Push(newNode);
70  base.VisitObjectMember(container, containerDescriptor, member, value);
71  stackItems.Pop();
72  }
73 
74  public override void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
75  {
76  var node = stackItems.Peek();
77  // TODO modify DataVisitorBase to allow only IList?
78  var newNode = new DataVisitListItem(index, item, itemDescriptor);
79  AddItem(node, newNode);
80 
81  stackItems.Push(newNode);
82  base.VisitCollectionItem(collection, descriptor, index, item, itemDescriptor);
83  stackItems.Pop();
84  }
85 
86  public override void VisitDictionaryKeyValue(object dictionary, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor)
87  {
88  var node = stackItems.Peek();
89  // TODO modify DataVisitorBase to allow only IDictionary?
90  var newNode = new DataVisitDictionaryItem(key, keyDescriptor, value, valueDescriptor);
91  AddItem(node, newNode);
92 
93  stackItems.Push(newNode);
94  base.VisitDictionaryKeyValue(dictionary, descriptor, key, keyDescriptor, value, valueDescriptor);
95  stackItems.Pop();
96  }
97 
98  public override void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
99  {
100  var node = stackItems.Peek();
101  var newNode = new DataVisitArrayItem(index, item, itemDescriptor);
102  AddItem(node, newNode);
103 
104  stackItems.Push(newNode);
105  base.VisitArrayItem(array, descriptor, index, item, itemDescriptor);
106  stackItems.Pop();
107  }
108 
109  /// <summary>
110  /// Adds a member to a <see cref="DataVisitNode"/> instance.
111  /// </summary>
112  /// <param name="thisObject">The this object.</param>
113  /// <param name="member">The member.</param>
114  /// <exception cref="System.ArgumentNullException">member</exception>
115  private static void AddMember(DataVisitNode thisObject, DataVisitNode member)
116  {
117  if (member == null) throw new ArgumentNullException("member");
118  if (thisObject.Members == null)
119  thisObject.Members = new List<DataVisitNode>();
120 
121  member.Parent = thisObject;
122  thisObject.Members.Add(member);
123  }
124 
125  /// <summary>
126  /// Adds an item (array, list or dictionary item) to a <see cref="DataVisitNode"/> instance.
127  /// </summary>
128  /// <param name="thisObject">The this object.</param>
129  /// <param name="item">The item.</param>
130  /// <exception cref="System.ArgumentNullException">item</exception>
131  private static void AddItem(DataVisitNode thisObject, DataVisitNode item)
132  {
133  if (item == null) throw new ArgumentNullException("item");
134  if (thisObject.Items == null)
135  thisObject.Items = new List<DataVisitNode>();
136 
137  item.Parent = thisObject;
138  thisObject.Items.Add(item);
139  }
140 
141  private static bool AcceptMember(IMemberDescriptor member)
142  {
143  // Skip some properties that are not using when visiting
144  if ((typeof(AssetImport).IsAssignableFrom(member.DeclaringType) && (member.Name == "ImporterId" || member.Name == "SourceHash"))
145  || typeof(Asset).IsAssignableFrom(member.DeclaringType) && (member.Name == "~Base" || member.Name == "Id"))
146  {
147  return false;
148  }
149 
150  return true;
151  }
152  }
153 }
Provides a descriptor for a System.Collections.ICollection.
override void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value)
Visits an object member.
A diff element for a member (field or property) of a class.
Default implementation of a ITypeDescriptor.
A visitor for producing a DataVisitNode for an object hierarchy.
Type DeclaringType
Gets the type that is declaring this member.
override void VisitDictionaryKeyValue(object dictionary, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor)
Visits a dictionary key-value.
static DataVisitObject Run(ITypeDescriptorFactory typeDescriptorFactory, object rootInstance)
Creates DataVisitNode from the specified instance.
The root node used for storing a hierarchy of DataVisitNode
Provides a descriptor for a System.Collections.IDictionary.
override void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
Visits a collection item.
Base class for all items in a collection (array, list or dictionary)
Provides access members of a type.
override void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
Visits an array item.
A factory to create an instance of a ITypeDescriptor