4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Collections.ObjectModel;
7 using System.Reflection;
8 using SiliconStudio.Core.Reflection;
9 using SiliconStudio.Core.Serialization.Serializers;
11 namespace SiliconStudio.Core
28 [DataSerializer(typeof(PropertyContainer.Serializer))]
31 private static readonly Dictionary<Type, List<PropertyKey>> accessorProperties =
new Dictionary<Type, List<PropertyKey>>();
32 private Dictionary<PropertyKey, object> properties;
34 private static ReadOnlyCollection<PropertyKey> emptyKeys =
new ReadOnlyCollection<PropertyKey>(
new List<PropertyKey>());
35 private static ReadOnlyCollection<object> emptyValues =
new ReadOnlyCollection<object>(
new List<object>());
44 public delegate
void PropertyUpdatedDelegate(ref
PropertyContainer propertyContainer,
PropertyKey propertyKey,
object newValue,
object oldValue);
54 PropertyUpdated = null;
75 if (properties != null)
77 foreach (var property
in properties)
79 yield
return new KeyValuePair<PropertyKey, object>(property.Key, property.Value);
85 var currentType = Owner.GetType();
86 while (currentType != null)
88 List<PropertyKey> typeAccessorProperties;
89 if (accessorProperties.TryGetValue(currentType, out typeAccessorProperties))
91 foreach (var accessorProperty
in typeAccessorProperties)
93 yield
return new KeyValuePair<PropertyKey, object>(accessorProperty, accessorProperty.AccessorMetadata.GetValue(ref
this));
97 currentType = currentType.GetTypeInfo().BaseType;
104 if (properties != null) properties.Clear();
115 return properties != null ? properties.Count : 0;
119 public bool IsReadOnly
135 SetObject(key, value,
true);
147 return properties != null && properties.ContainsKey(key);
152 SetObject(key, value,
true);
157 bool removed =
false;
159 if (PropertyUpdated != null || propertyKey.PropertyUpdateCallback != null)
161 object previousValue = Get(propertyKey);
163 if (properties != null)
164 removed = properties.Remove(propertyKey);
165 var tagValue = Get(propertyKey);
167 if (!ArePropertyValuesEqual(propertyKey, tagValue, previousValue))
169 if (propertyKey.PropertyUpdateCallback != null)
170 propertyKey.PropertyUpdateCallback(ref
this, propertyKey, tagValue, previousValue);
171 if (PropertyUpdated != null)
172 PropertyUpdated(ref
this, propertyKey, tagValue, previousValue);
177 if (properties != null)
178 removed = properties.Remove(propertyKey);
192 SetObject(key, value);
209 if (properties != null)
return properties.Values;
220 foreach (var keyValuePair
in this)
221 destination.SetObject(keyValuePair.Key, keyValuePair.Value);
231 return Get(propertyKey,
false);
234 private object Get(
PropertyKey propertyKey,
bool forceNotToKeep)
239 return propertyKey.AccessorMetadata.GetValue(ref
this);
245 if (properties != null && properties.TryGetValue(propertyKey, out value))
248 value = ((ValueHolder)value).ObjectValue;
255 object defaultValue = propertyKey.DefaultValueMetadata.GetDefaultValue(ref
this);
261 SetObject(propertyKey, defaultValue);
284 return (T)propertyKey.AccessorMetadata.GetValue(ref
this);
290 if (properties != null && properties.TryGetValue(propertyKey, out value))
291 return ((ValueHolder<T>)value).Value;
302 Set(propertyKey, defaultValue);
312 return result != null ? (T)result :
default(T);
325 if (ContainsKey(propertyKey))
327 var result = Get(propertyKey);
345 if (ContainsKey(propertyKey))
347 value = Get<T>(propertyKey);
364 ValueHolder<T> valueHolder = null;
380 if (properties != null && properties.TryGetValue(propertyKey, out value))
382 valueHolder = (ValueHolder<T>)value;
383 oldValue = valueHolder.Value;
388 oldValue = propertyKey.DefaultValueMetadataT.GetDefaultValueT(ref
this);
392 oldValue =
default(T);
400 propertyKey.ValidateValueMetadataT.ValidateValueCallback(ref tagValue);
407 propertyKey.AccessorMetadata.SetValue(ref
this, tagValue);
411 if (properties == null)
412 properties =
new Dictionary<PropertyKey, object>();
414 if (valueHolder != null)
415 valueHolder.Value = tagValue;
417 valueHolder =
new ValueHolder<T>(tagValue);
419 if (PropertyUpdated != null || propertyKey.PropertyUpdateCallback != null)
421 object previousValue = GetNonRecursive(propertyKey);
423 properties[propertyKey] = valueHolder;
425 if (!ArePropertyValuesEqual(propertyKey, tagValue, previousValue))
427 if (PropertyUpdated != null)
428 PropertyUpdated(ref
this, propertyKey, tagValue, previousValue);
429 if (propertyKey.PropertyUpdateCallback != null)
430 propertyKey.PropertyUpdateCallback(ref
this, propertyKey, tagValue, previousValue);
435 properties[propertyKey] = valueHolder;
440 propertyKey.ObjectInvalidationMetadataT.Invalidate(Owner, propertyKey, ref oldValue);
446 SetObject((
PropertyKey)propertyKey, tagValue,
false);
456 SetObject(propertyKey, tagValue,
false);
459 private void SetObject(
PropertyKey propertyKey,
object tagValue,
bool tryToAdd =
false)
461 var oldValue = Get(propertyKey,
true);
466 propertyKey.ValidateValueMetadata.Validate(ref tagValue);
472 propertyKey.AccessorMetadata.SetValue(ref
this, tagValue);
476 if (properties == null)
477 properties =
new Dictionary<PropertyKey, object>();
479 var valueToSet = propertyKey.IsValueType ? propertyKey.CreateValueHolder(tagValue) : tagValue;
481 if (PropertyUpdated != null || propertyKey.PropertyUpdateCallback != null)
483 object previousValue = GetNonRecursive(propertyKey);
486 properties.Add(propertyKey, valueToSet);
488 properties[propertyKey] = valueToSet;
490 if (!ArePropertyValuesEqual(propertyKey, tagValue, previousValue))
492 if (PropertyUpdated != null)
493 PropertyUpdated(ref
this, propertyKey, tagValue, previousValue);
494 if (propertyKey.PropertyUpdateCallback != null)
495 propertyKey.PropertyUpdateCallback(ref
this, propertyKey, tagValue, previousValue);
501 properties.Add(propertyKey, valueToSet);
503 properties[propertyKey] = valueToSet;
506 if (propertyKey.ObjectInvalidationMetadata != null)
508 propertyKey.ObjectInvalidationMetadata.Invalidate(Owner, propertyKey, oldValue);
514 if (!type.GetTypeInfo().IsClass)
515 throw new ArgumentException(
"Class type is expected.",
"type");
518 throw new ArgumentException(
"Given PropertyKey doesn't have accessor metadata.",
"propertyKey");
520 List<PropertyKey> typeAccessorProperties;
521 if (!accessorProperties.TryGetValue(type, out typeAccessorProperties))
522 accessorProperties.Add(type, typeAccessorProperties =
new List<PropertyKey>());
524 typeAccessorProperties.Add(propertyKey);
527 internal void RaisePropertyContainerUpdated(
PropertyKey propertyKey,
object newValue,
object oldValue)
529 if (PropertyUpdated != null)
530 PropertyUpdated(ref
this, propertyKey, newValue, oldValue);
533 private object GetNonRecursive(PropertyKey propertyKey)
538 if (properties != null && properties.TryGetValue(propertyKey, out value))
540 if (propertyKey.IsValueType)
541 return ((ValueHolder)value).ObjectValue;
545 if (propertyKey.DefaultValueMetadata != null)
548 return propertyKey.DefaultValueMetadata.GetDefaultValue(ref
this);
554 private static bool ArePropertyValuesEqual(PropertyKey propertyKey,
object propertyValue1,
object propertyValue2)
556 var propertyType = propertyKey.PropertyType;
558 if (!propertyType.GetTypeInfo().IsValueType && propertyType != typeof(
string))
560 return object.ReferenceEquals(propertyValue1, propertyValue2);
563 return object.Equals(propertyValue1, propertyValue2);
566 IEnumerator IEnumerable.GetEnumerator()
568 return GetEnumerator();
608 internal abstract class ValueHolder
610 public abstract object ObjectValue {
get; }
613 internal class ValueHolder<T> : ValueHolder
617 public ValueHolder(T value)
622 public override object ObjectValue
624 get {
return Value; }
AccessorMetadata AccessorMetadata
Gets the accessor metadata (may be null).
static void AddAccessorProperty(Type type, PropertyKey propertyKey)
DefaultValueMetadata DefaultValueMetadata
Gets the default value metadata.
ValidateValueMetadata ValidateValueMetadata
Gets the validate value metadata (may be null).
Represents a container that can hold properties, lightweight to embed (lazy initialized).
SiliconStudio.Paradox.Input.Keys Keys
void CopyTo(ref PropertyContainer destination)
Copies properties from this instance to a container.
abstract bool IsValueType
bool ContainsKey(PropertyKey key)
Determines whether the specified instance contains this key.
IEnumerator< KeyValuePair< PropertyKey, object > > GetEnumerator()
Gets the key-properties value pairs in this instance.
void SetObject(PropertyKey propertyKey, object tagValue)
Sets the specified tag value.
ObjectInvalidationMetadata ObjectInvalidationMetadata
Gets the object invalidation metadata (may be null).
PropertyContainer(object owner)
A class that represents a typed tag propety.
void Add(PropertyKey key, object value)
bool TryGetValue(PropertyKey propertyKey, out object value)
Tries to get a tag value.
bool Remove(PropertyKey propertyKey)
A class that represents a tag propety.
object Get(PropertyKey propertyKey)
Gets the specified tag value.
PropertyUpdatedDelegate PropertyUpdated
Occurs when a property is modified.