From a9f12cbb437ee0c5d2e9f842ef8b8095f8bed732 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 9 Nov 2022 15:48:33 +0100 Subject: [PATCH] Avoid boxing in EffectiveValue.SetAndRaise. Added `IValueEntry` interface back in and use that if present to get the value from the entry. --- .../PropertyStore/BindingEntryBase.cs | 11 +++++++++-- .../PropertyStore/EffectiveValue`1.cs | 11 ++++++++++- src/Avalonia.Base/PropertyStore/IValueEntry`1.cs | 16 ++++++++++++++++ .../PropertyStore/ImmediateValueEntry.cs | 3 ++- 4 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 src/Avalonia.Base/PropertyStore/IValueEntry`1.cs diff --git a/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs b/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs index 5b7e9adf6d..ef14211902 100644 --- a/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs +++ b/src/Avalonia.Base/PropertyStore/BindingEntryBase.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reactive.Disposables; using Avalonia.Data; namespace Avalonia.PropertyStore { - internal abstract class BindingEntryBase : IValueEntry, + internal abstract class BindingEntryBase : IValueEntry, IObserver, IObserver>, IDisposable @@ -58,6 +57,14 @@ namespace Avalonia.PropertyStore BindingCompleted(); } + public TValue GetValue() + { + Start(produceValue: false); + if (!_hasValue) + throw new AvaloniaInternalException("The binding entry has no value."); + return _value!; + } + public void Start() => Start(true); public void OnCompleted() => BindingCompleted(); diff --git a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs index 3dd12b911b..20d708b20e 100644 --- a/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs +++ b/src/Avalonia.Base/PropertyStore/EffectiveValue`1.cs @@ -55,7 +55,8 @@ namespace Avalonia.PropertyStore { Debug.Assert(priority != BindingPriority.LocalValue); UpdateValueEntry(value, priority); - SetAndRaiseCore(owner, (StyledPropertyBase)value.Property, (T)value.GetValue()!, priority); + + SetAndRaiseCore(owner, (StyledPropertyBase)value.Property, GetValue(value), priority); } public void SetLocalValueAndRaise( @@ -144,6 +145,14 @@ namespace Avalonia.PropertyStore protected override object? GetBoxedValue() => Value; + private static T GetValue(IValueEntry entry) + { + if (entry is IValueEntry typed) + return typed.GetValue(); + else + return (T)entry.GetValue()!; + } + private void SetAndRaiseCore( ValueStore owner, StyledPropertyBase property, diff --git a/src/Avalonia.Base/PropertyStore/IValueEntry`1.cs b/src/Avalonia.Base/PropertyStore/IValueEntry`1.cs new file mode 100644 index 0000000000..5b69009e79 --- /dev/null +++ b/src/Avalonia.Base/PropertyStore/IValueEntry`1.cs @@ -0,0 +1,16 @@ +namespace Avalonia.PropertyStore +{ + /// + /// Represents a typed value entry in a . + /// + internal interface IValueEntry : IValueEntry + { + /// + /// Gets the value associated with the entry. + /// + /// + /// The entry has no value. + /// + new T GetValue(); + } +} diff --git a/src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs b/src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs index 6040a7a328..364b4e1225 100644 --- a/src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/ImmediateValueEntry.cs @@ -2,7 +2,7 @@ namespace Avalonia.PropertyStore { - internal class ImmediateValueEntry : IValueEntry, IDisposable + internal class ImmediateValueEntry : IValueEntry, IDisposable { private readonly ImmediateValueFrame _owner; private readonly T _value; @@ -26,5 +26,6 @@ namespace Avalonia.PropertyStore public void Dispose() => _owner.OnEntryDisposed(this); object? IValueEntry.GetValue() => _value; + T IValueEntry.GetValue() => _value; } }