Browse Source

Merge pull request #2935 from MarchingCube/fix-styledproperty-defaultvalue-box

Avoid constant boxing of StyledProperty default value.
Steven Kirk 6 years ago
parent
commit
8c36203e20

+ 28 - 0
src/Avalonia.Base/BoxedValue.cs

@@ -0,0 +1,28 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+namespace Avalonia
+{
+    /// <summary>
+    /// Represents boxed value of type <typeparamref name="T"/>.
+    /// </summary>
+    /// <typeparam name="T">Type of stored value.</typeparam>
+    internal readonly struct BoxedValue<T>
+    {
+        public BoxedValue(T value)
+        {
+            Boxed = value;
+            Typed = value;
+        }
+
+        /// <summary>
+        /// Boxed value.
+        /// </summary>
+        public object Boxed { get; }
+
+        /// <summary>
+        /// Typed value.
+        /// </summary>
+        public T Typed { get; }
+    }
+}

+ 9 - 2
src/Avalonia.Base/StyledPropertyBase.cs

@@ -68,7 +68,7 @@ namespace Avalonia
         {
             Contract.Requires<ArgumentNullException>(type != null);
 
-            return GetMetadata(type).DefaultValue;
+            return GetMetadata(type).DefaultValue.Typed;
         }
 
         /// <summary>
@@ -164,7 +164,14 @@ namespace Avalonia
         }
 
         /// <inheritdoc/>
-        object IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultValue(type);
+        object IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultBoxedValue(type);
+
+        private object GetDefaultBoxedValue(Type type)
+        {
+            Contract.Requires<ArgumentNullException>(type != null);
+
+            return GetMetadata(type).DefaultValue.Boxed;
+        }
 
         [DebuggerHidden]
         private Func<IAvaloniaObject, TValue, TValue> Cast<THost>(Func<THost, TValue, TValue> validate)

+ 6 - 8
src/Avalonia.Base/StyledPropertyMetadata`1.cs

@@ -19,26 +19,26 @@ namespace Avalonia
         /// <param name="validate">A validation function.</param>
         /// <param name="defaultBindingMode">The default binding mode.</param>
         public StyledPropertyMetadata(
-            TValue defaultValue = default(TValue),
+            TValue defaultValue = default,
             Func<IAvaloniaObject, TValue, TValue> validate = null,
             BindingMode defaultBindingMode = BindingMode.Default)
                 : base(defaultBindingMode)
         {
-            DefaultValue = defaultValue;
+            DefaultValue = new BoxedValue<TValue>(defaultValue);
             Validate = validate;
         }
 
         /// <summary>
         /// Gets the default value for the property.
         /// </summary>
-        public TValue DefaultValue { get; private set; }
+        internal BoxedValue<TValue> DefaultValue { get; private set; }
 
         /// <summary>
         /// Gets the validation callback.
         /// </summary>
         public Func<IAvaloniaObject, TValue, TValue> Validate { get; private set; }
 
-        object IStyledPropertyMetadata.DefaultValue => DefaultValue;
+        object IStyledPropertyMetadata.DefaultValue => DefaultValue.Boxed;
 
         Func<IAvaloniaObject, object, object> IStyledPropertyMetadata.Validate => Cast(Validate);
 
@@ -47,11 +47,9 @@ namespace Avalonia
         {
             base.Merge(baseMetadata, property);
 
-            var src = baseMetadata as StyledPropertyMetadata<TValue>;
-
-            if (src != null)
+            if (baseMetadata is StyledPropertyMetadata<TValue> src)
             {
-                if (DefaultValue == null)
+                if (DefaultValue.Boxed == null)
                 {
                     DefaultValue = src.DefaultValue;
                 }