Browse Source

performance optimization of

- AvaloniaObject.GetValue
- AvaloniaPropertyRegistry.IsRegistered
- AvaloniaProperty.GetMetadata
pull/558/head
donandren 10 years ago
parent
commit
7c5545f108
  1. 45
      src/Avalonia.Base/AvaloniaObject.cs
  2. 54
      src/Avalonia.Base/AvaloniaProperty.cs
  3. 44
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs

45
src/Avalonia.Base/AvaloniaObject.cs

@ -261,25 +261,12 @@ namespace Avalonia
}
else
{
object result = AvaloniaProperty.UnsetValue;
PriorityValue value;
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property))
{
ThrowNotRegistered(property);
}
if (_values.TryGetValue(property, out value))
{
result = value.Value;
}
if (result == AvaloniaProperty.UnsetValue)
{
result = GetDefaultValue(property);
}
return result;
return GetValueInternal(property);
}
}
@ -767,7 +754,7 @@ namespace Avalonia
{
if (property.Inherits && _inheritanceParent != null)
{
return _inheritanceParent.GetValue(property);
return (_inheritanceParent as AvaloniaObject).GetValueInternal(property);
}
else
{
@ -775,6 +762,32 @@ namespace Avalonia
}
}
/// <summary>
/// Gets a <see cref="AvaloniaProperty"/> value
/// without check for registered as this can slow getting the value
/// this method is intended for internal usage in AvaloniaObject only
/// it's called only after check the property is registered
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
private object GetValueInternal(AvaloniaProperty property)
{
object result = AvaloniaProperty.UnsetValue;
PriorityValue value;
if (_values.TryGetValue(property, out value))
{
result = value.Value;
}
if (result == AvaloniaProperty.UnsetValue)
{
result = GetDefaultValue(property);
}
return result;
}
/// <summary>
/// Given a <see cref="AvaloniaProperty"/> returns a registered avalonia property that is
/// equal or throws if not found.
@ -849,4 +862,4 @@ namespace Avalonia
throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}");
}
}
}
}

54
src/Avalonia.Base/AvaloniaProperty.cs

@ -26,6 +26,7 @@ namespace Avalonia
private readonly Subject<AvaloniaPropertyChangedEventArgs> _changed;
private readonly PropertyMetadata _defaultMetadata;
private readonly Dictionary<Type, PropertyMetadata> _metadata;
private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>();
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty"/> class.
@ -73,8 +74,8 @@ namespace Avalonia
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
protected AvaloniaProperty(
AvaloniaProperty source,
Type ownerType,
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
{
Contract.Requires<ArgumentNullException>(source != null);
@ -163,11 +164,11 @@ namespace Avalonia
/// object.
/// </summary>
/// <remarks>
/// When a property changes, change notifications are sent to all property subscribers;
/// for example via the <see cref="AvaloniaProperty.Changed"/> observable and and the
/// When a property changes, change notifications are sent to all property subscribers;
/// for example via the <see cref="AvaloniaProperty.Changed"/> observable and and the
/// <see cref="AvaloniaObject.PropertyChanged"/> event. If this callback is set for a property,
/// then it will be called before and after these notifications take place. The bool argument
/// will be true before the property change notifications are sent and false afterwards. This
/// will be true before the property change notifications are sent and false afterwards. This
/// callback is intended to support Control.IsDataContextChanging.
/// </remarks>
public Action<IAvaloniaObject, bool> Notifying { get; }
@ -273,8 +274,8 @@ namespace Avalonia
defaultBindingMode: defaultBindingMode);
var result = new StyledProperty<TValue>(
name,
typeof(TOwner),
name,
typeof(TOwner),
metadata,
inherits,
notifying);
@ -423,24 +424,9 @@ namespace Avalonia
/// </returns>
public PropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
{
var type = typeof(T);
while (type != null)
{
PropertyMetadata result;
if (_metadata.TryGetValue(type, out result))
{
return result;
}
type = type.GetTypeInfo().BaseType;
}
return _defaultMetadata;
return GetMetadata(typeof(T));
}
/// <summary>
/// Gets the property metadata for the specified type.
/// </summary>
@ -448,22 +434,33 @@ namespace Avalonia
/// <returns>
/// The property metadata.
/// </returns>
///
public PropertyMetadata GetMetadata(Type type)
{
Contract.Requires<ArgumentNullException>(type != null);
while (type != null)
PropertyMetadata result;
Type currentType = type;
if (_metadataCache.TryGetValue(type, out result))
{
PropertyMetadata result;
return result;
}
if (_metadata.TryGetValue(type, out result))
while (currentType != null)
{
if (_metadata.TryGetValue(currentType, out result))
{
_metadataCache[type] = result;
return result;
}
type = type.GetTypeInfo().BaseType;
currentType = currentType.GetTypeInfo().BaseType;
}
_metadataCache[type] = _defaultMetadata;
return _defaultMetadata;
}
@ -523,6 +520,7 @@ namespace Avalonia
var baseMetadata = GetMetadata(type);
metadata.Merge(baseMetadata, this);
_metadata.Add(type, metadata);
_metadataCache.Clear();
}
[DebuggerHidden]
@ -551,4 +549,4 @@ namespace Avalonia
public override string ToString() => "(unset)";
}
}
}
}

44
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -20,6 +20,12 @@ namespace Avalonia
private readonly Dictionary<Type, Dictionary<int, AvaloniaProperty>> _registered =
new Dictionary<Type, Dictionary<int, AvaloniaProperty>>();
/// <summary>
/// The registered properties by type cached values to increase performance.
/// </summary>
private readonly Dictionary<Type, Dictionary<int, AvaloniaProperty>> _registeredCache =
new Dictionary<Type, Dictionary<int, AvaloniaProperty>>();
/// <summary>
/// The registered attached properties by owner type.
/// </summary>
@ -103,21 +109,38 @@ namespace Avalonia
/// </remarks>
public AvaloniaProperty FindRegistered(Type type, AvaloniaProperty property)
{
while (type != null)
Type currentType = type;
Dictionary<int, AvaloniaProperty> cache;
AvaloniaProperty result;
if (_registeredCache.TryGetValue(type, out cache))
{
if (cache.TryGetValue(property.Id, out result))
{
return result;
}
}
while (currentType != null)
{
Dictionary<int, AvaloniaProperty> inner;
if (_registered.TryGetValue(type, out inner))
if (_registered.TryGetValue(currentType, out inner))
{
AvaloniaProperty result;
if (inner.TryGetValue(property.Id, out result))
{
if (cache == null)
{
_registeredCache[type] = cache = new Dictionary<int, AvaloniaProperty>();
}
cache[property.Id] = result;
return result;
}
}
type = type.GetTypeInfo().BaseType;
currentType = currentType.GetTypeInfo().BaseType;
}
return null;
@ -130,7 +153,7 @@ namespace Avalonia
/// <param name="property">The property.</param>
/// <returns>The registered property or null if not found.</returns>
/// <remarks>
/// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a
/// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a
/// different object but is equal according to <see cref="object.Equals(object)"/>.
/// </remarks>
public AvaloniaProperty FindRegistered(object o, AvaloniaProperty property)
@ -143,7 +166,7 @@ namespace Avalonia
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">
/// The property name. If an attached property it should be in the form
/// The property name. If an attached property it should be in the form
/// "OwnerType.PropertyName".
/// </param>
/// <returns>
@ -183,13 +206,12 @@ namespace Avalonia
return results.FirstOrDefault(x => x.Name == propertyName);
}
/// <summary>
/// Finds a registered property on an object by name.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="name">
/// The property name. If an attached property it should be in the form
/// The property name. If an attached property it should be in the form
/// "OwnerType.PropertyName".
/// </param>
/// <returns>
@ -276,6 +298,8 @@ namespace Avalonia
inner.Add(property.Id, property);
}
}
_registeredCache.Clear();
}
}
}
}
Loading…
Cancel
Save