Browse Source

Avoid initializing properties if there is no observer. Optimize access.

pull/2910/head
Dariusz Komosinski 7 years ago
parent
commit
addc1ddce2
  1. 5
      src/Avalonia.Base/AvaloniaProperty.cs
  2. 74
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs
  3. 15
      tests/Avalonia.Benchmarks/Base/AvaloniaObjectInitializationBenchmark.cs

5
src/Avalonia.Base/AvaloniaProperty.cs

@ -492,6 +492,11 @@ namespace Avalonia
return Name;
}
/// <summary>
/// True if <see cref="Initialized"/> has any observers.
/// </summary>
internal bool HasNotifyInitializedObservers => _initialized.HasObservers;
/// <summary>
/// Notifies the <see cref="Initialized"/> observable.
/// </summary>

74
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -24,8 +24,8 @@ namespace Avalonia
new Dictionary<Type, List<AvaloniaProperty>>();
private readonly Dictionary<Type, List<AvaloniaProperty>> _attachedCache =
new Dictionary<Type, List<AvaloniaProperty>>();
private readonly Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>> _initializedCache =
new Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>>();
private readonly Dictionary<Type, List<PropertyInitializationData>> _initializedCache =
new Dictionary<Type, List<PropertyInitializationData>>();
/// <summary>
/// Gets the <see cref="AvaloniaPropertyRegistry"/> instance
@ -286,35 +286,73 @@ namespace Avalonia
property.NotifyInitialized(e);
}
if (!_initializedCache.TryGetValue(type, out var items))
if (!_initializedCache.TryGetValue(type, out var initializationData))
{
var build = new Dictionary<AvaloniaProperty, object>();
var visited = new HashSet<AvaloniaProperty>();
foreach (var property in GetRegistered(type))
initializationData = new List<PropertyInitializationData>();
foreach (AvaloniaProperty property in GetRegistered(type))
{
var value = !property.IsDirect ?
((IStyledPropertyAccessor)property).GetDefaultValue(type) :
null;
build.Add(property, value);
if (property.IsDirect)
{
initializationData.Add(new PropertyInitializationData(property, (IDirectPropertyAccessor)property));
}
else
{
initializationData.Add(new PropertyInitializationData(property, (IStyledPropertyAccessor)property, type));
}
visited.Add(property);
}
foreach (var property in GetRegisteredAttached(type))
foreach (AvaloniaProperty property in GetRegisteredAttached(type))
{
if (!build.ContainsKey(property))
if (!visited.Contains(property))
{
var value = ((IStyledPropertyAccessor)property).GetDefaultValue(type);
build.Add(property, value);
initializationData.Add(new PropertyInitializationData(property, (IStyledPropertyAccessor)property, type));
visited.Add(property);
}
}
items = build.ToList();
_initializedCache.Add(type, items);
_initializedCache.Add(type, initializationData);
}
foreach (PropertyInitializationData data in initializationData)
{
if (!data.Property.HasNotifyInitializedObservers)
{
continue;
}
object value = data.IsDirect ? data.DirectAccessor.GetValue(o) : data.Value;
Notify(data.Property, value);
}
}
private readonly struct PropertyInitializationData
{
public AvaloniaProperty Property { get; }
public object Value { get; }
public bool IsDirect { get; }
public IDirectPropertyAccessor DirectAccessor { get; }
public PropertyInitializationData(AvaloniaProperty property, IDirectPropertyAccessor directAccessor)
{
Property = property;
Value = null;
IsDirect = true;
DirectAccessor = directAccessor;
}
foreach (var i in items)
public PropertyInitializationData(AvaloniaProperty property, IStyledPropertyAccessor styledAccessor, Type type)
{
var value = i.Key.IsDirect ? o.GetValue(i.Key) : i.Value;
Notify(i.Key, value);
Property = property;
Value = styledAccessor.GetDefaultValue(type);
IsDirect = false;
DirectAccessor = null;
}
}
}

15
tests/Avalonia.Benchmarks/Base/AvaloniaObjectInitializationBenchmark.cs

@ -0,0 +1,15 @@
using Avalonia.Controls;
using BenchmarkDotNet.Attributes;
namespace Avalonia.Benchmarks.Base
{
[MemoryDiagnoser]
public class AvaloniaObjectInitializationBenchmark
{
[Benchmark(OperationsPerInvoke = 1000)]
public Button InitializeButton()
{
return new Button();
}
}
}
Loading…
Cancel
Save