Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ReferenceEnumerable.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 using SiliconStudio.Core.Extensions;
9 using SiliconStudio.Core.Reflection;
10 
11 namespace SiliconStudio.Quantum.References
12 {
13  /// <summary>
14  /// A class representing an enumeration of references to multiple objects.
15  /// </summary>
16  public sealed class ReferenceEnumerable : IReference, IEnumerable<ObjectReference>
17  {
18  private readonly List<ObjectReference> references = new List<ObjectReference>();
19  private readonly List<object> indices = new List<object>();
20  private readonly Type elementType;
21 
22  internal ReferenceEnumerable(IEnumerable enumerable, Type enumerableType, object index)
23  {
24  Reference.CheckReferenceCreationSafeGuard();
25  Type = enumerableType;
26  Index = index;
27 
28  if (enumerableType.HasInterface(typeof(IDictionary<,>)))
29  elementType = enumerableType.GetInterface(typeof(IDictionary<,>)).GetGenericArguments()[1];
30  else if (enumerableType.HasInterface(typeof(IEnumerable<>)))
31  elementType = enumerableType.GetInterface(typeof(IEnumerable<>)).GetGenericArguments()[0];
32  else
33  elementType = typeof(object);
34 
35  Refresh(enumerable);
36  }
37 
38  /// <inheritdoc/>
39  public object ObjectValue { get; private set; }
40 
41  /// <inheritdoc/>
42  public Type Type { get; private set; }
43 
44  /// <inheritdoc/>
45  public object Index { get; private set; }
46 
47  /// <summary>
48  /// Gets whether this reference enumerates a dictionary collection.
49  /// </summary>
50  public bool IsDictionary { get { return ObjectValue is IDictionary || ObjectValue.GetType().HasInterface(typeof(IDictionary<,>)); } }
51 
52  /// <inheritdoc/>
53  public int Count { get { return references.Count; } }
54 
55  /// <inheritdoc/>
56  public ObjectReference this[object index] { get { return references.Single(x => Equals(x.Index, index)); } }
57 
58  /// <inheritdoc/>
59  public void Clear()
60  {
61  references.Clear();
62  }
63 
64  /// <summary>
65  /// Indicates whether this instance of <see cref="ReferenceEnumerable"/> contains an element which as the given index.
66  /// </summary>
67  /// <param name="index">The index to look for.</param>
68  /// <returns><c>true</c> if an object with the given index exists in this instance, <c>false</c> otherwise.</returns>
69  public bool ContainsIndex(object index)
70  {
71  return references.Any(x => Equals(x.Index, index));
72  }
73 
74  /// <inheritdoc/>
75  public void Refresh(object newObjectValue)
76  {
77  if (!(newObjectValue is IEnumerable)) throw new ArgumentException(@"The object is not an IEnumerable", "newObjectValue");
78 
79  ObjectValue = newObjectValue;
80 
81  references.Clear();
82  references.AddRange(
83  IsDictionary
84  ? ((IEnumerable)ObjectValue).Cast<object>().Select(x => (ObjectReference)Reference.CreateReference(GetValue(x), elementType, GetKey(x)))
85  : ((IEnumerable)ObjectValue).Cast<object>().Select((x, i) => (ObjectReference)Reference.CreateReference(x, elementType, i)));
86  indices.Clear();
87  foreach (var reference in references)
88  {
89  indices.Add(reference.Index);
90  }
91  }
92 
93  /// <inheritdoc/>
94  public bool UpdateTarget(ModelContainer modelContainer)
95  {
96  bool result = false;
97  foreach (var reference in references)
98  {
99  if (reference.UpdateTarget(modelContainer))
100  result = true;
101  }
102 
103  return result;
104  }
105 
106  /// <inheritdoc/>
107  public IEnumerator<ObjectReference> GetEnumerator()
108  {
109  return references.GetEnumerator();
110  }
111 
112  /// <inheritdoc/>
113  IEnumerator IEnumerable.GetEnumerator()
114  {
115  return references.GetEnumerator();
116  }
117 
118  /// <inheritdoc/>
119  public bool Equals(IReference other)
120  {
121  var otherEnumerable = other as ReferenceEnumerable;
122  return otherEnumerable != null && DesignExtensions.Equals<IReference>(references, otherEnumerable.references);
123  }
124 
125  /// <inheritdoc/>
126  public override string ToString()
127  {
128  string text = "(" + references.Count + " references";
129  if (references.Count > 0)
130  {
131  text += ": ";
132  text += string.Join(", ", references);
133  }
134  text += ")";
135  return text;
136  }
137 
138  private static object GetKey(object keyValuePair)
139  {
140  var type = keyValuePair.GetType();
141  if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(KeyValuePair<,>)) throw new ArgumentException("The given object is not a KeyValuePair.");
142  var keyProperty = type.GetProperty("Key");
143  return keyProperty.GetValue(keyValuePair);
144  }
145 
146  private static object GetValue(object keyValuePair)
147  {
148  var type = keyValuePair.GetType();
149  if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(KeyValuePair<,>)) throw new ArgumentException("The given object is not a KeyValuePair.");
150  var valueProperty = type.GetProperty("Value");
151  return valueProperty.GetValue(keyValuePair);
152  }
153  }
154 }
void Refresh(object newObjectValue)
Refresh this reference and its nested references.
A container used to store models and resolve references between them.
void Clear()
Clear the reference, making it represent a null or empty object.
A class representing an enumeration of references to multiple objects.
bool ContainsIndex(object index)
Indicates whether this instance of ReferenceEnumerable contains an element which as the given index...
bool UpdateTarget(ModelContainer modelContainer)
Updates the target node of this reference or its nested references from a ModelContainer. A ModelContainer in which the corresponding model node may have been registered.true if the model node was found in the ModelContainer and the target nodes has been updated, false otherwise.
A class representing a reference to another object that has a different model.