Skip to content

Commit

Permalink
chore: Address review comments on DependencyPropertyHelper PR
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Sep 15, 2024
1 parent a32e269 commit 3bae203
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public void When_GetPropertyType()
var property = TestClass.TestProperty;

// Act
var propertyType = DependencyPropertyHelper.GetValueType(property);
var propertyType = DependencyPropertyHelper.GetPropertyType(property);

// Assert
propertyType.Should().Be(typeof(string));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ namespace Microsoft.UI.Xaml
{
public sealed partial class DependencyProperty
{
private class DependencyPropertyRegistry
internal class DependencyPropertyRegistry
{
public static DependencyPropertyRegistry Instance { get; } = new DependencyPropertyRegistry();

// This dictionary has a single static instance that is kept for the lifetime of the whole app.
// So we don't use pooling to not cause pool exhaustion by renting without returning.
private readonly HashtableEx _entries = new HashtableEx(FastTypeComparer.Default, usePooling: false);

private DependencyPropertyRegistry()
{
}

internal bool TryGetValue(Type type, string name, out DependencyProperty? result)
{
if (TryGetTypeTable(type, out var typeTable))
Expand All @@ -39,8 +45,6 @@ internal bool TryGetValue(Type type, string name, out DependencyProperty? result
return false;
}

internal void Clear() => _entries.Clear();

internal void Add(Type type, string name, DependencyProperty property)
{
if (!TryGetTypeTable(type, out var typeTable))
Expand All @@ -63,7 +67,7 @@ internal void AppendPropertiesForType(Type type, List<DependencyProperty> proper
}
}

private bool TryGetTypeTable(Type type, out HashtableEx? table)
internal bool TryGetTypeTable(Type type, out HashtableEx? table)
{
if (_entries.TryGetValue(type, out var dictionaryObject))
{
Expand Down
15 changes: 2 additions & 13 deletions src/Uno.UI/UI/Xaml/DependencyProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace Microsoft.UI.Xaml
[DebuggerDisplay("Name={Name}, Type={Type.FullName}, Owner={OwnerType.FullName}")]
public sealed partial class DependencyProperty
{
private readonly static DependencyPropertyRegistry _registry = new DependencyPropertyRegistry();
private readonly static DependencyPropertyRegistry _registry = DependencyPropertyRegistry.Instance;

private readonly static TypeToPropertiesDictionary _getPropertiesForType = new TypeToPropertiesDictionary();
private readonly static NameToPropertyDictionary _getPropertyCache = new NameToPropertyDictionary();
Expand Down Expand Up @@ -416,17 +416,6 @@ internal static DependencyProperty[] GetFrameworkPropertiesForType(Type type, Fr
return result;
}

/// <summary>
/// Clears all the property registrations, when used in unit tests.
/// </summary>
internal static void ClearRegistry()
{
_registry.Clear();
_getPropertiesForType.Clear();
_getPropertyCache.Clear();
_getFrameworkPropertiesForType.Clear();
}

private static void RegisterProperty(Type ownerType, string name, DependencyProperty newProperty)
{
ResetGetPropertyCache(ownerType, name);
Expand Down Expand Up @@ -469,7 +458,7 @@ private static DependencyProperty[] InternalGetPropertiesForType(Type type)
///
/// See: http://stackoverflow.com/questions/6729841/why-did-the-beforefieldinit-behavior-change-in-net-4
/// </remarks>
private static void ForceInitializeTypeConstructor(Type type)
internal static void ForceInitializeTypeConstructor(Type type)
{
do
{
Expand Down
63 changes: 45 additions & 18 deletions src/Uno.UI/UI/Xaml/Internal/DependencyPropertyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ internal static class DependencyPropertyHelper
/// </summary>
public static IReadOnlyCollection<DependencyProperty>? GetDependencyPropertiesForType<T>()
where T : DependencyObject
=> DependencyProperty.GetPropertiesForType(typeof(T));
=> GetPropertiesForTypeCore(typeof(T));

/// <summary>
/// Try to get all the <see cref="DependencyProperty"/> defined for a given type.
Expand All @@ -84,14 +84,45 @@ public static bool TryGetDependencyPropertiesForType(
return false;
}

properties = DependencyProperty.GetPropertiesForType(forType);
properties = GetPropertiesForTypeCore(forType);
return true;
}

private static DependencyProperty[] GetPropertiesForTypeCore(Type type)
{
DependencyProperty.ForceInitializeTypeConstructor(type);

var results = new List<DependencyProperty>();

var currentType = type;

do
{
if (DependencyProperty.DependencyPropertyRegistry.Instance.TryGetTypeTable(currentType, out var typeTable))
{
foreach (var value in typeTable!.Values)
{
results.Add((DependencyProperty)value);
}
}

// Dependency properties are inherited
currentType = currentType.BaseType;
}
while (currentType != typeof(object) && currentType != null);

var array = results.ToArray();

// Produce a pre-sorted list, aligned with the initial behavior of DependencyPropertyDetailsCollection
Array.Sort(array, (l, r) => l.UniqueId - r.UniqueId);

return array;
}

/// <summary>
/// Get the value type of the property.
/// Get the type of the property.
/// </summary>
public static Type GetValueType(DependencyProperty dependencyProperty)
public static Type GetPropertyType(DependencyProperty dependencyProperty)
=> dependencyProperty.Type;

/// <summary>
Expand All @@ -105,7 +136,6 @@ public static string GetName(DependencyProperty dependencyProperty)
/// </summary>
/// <remarks>
/// This is the property that defines the property, not the type that uses it.
/// It may also be overridden by a derived type.
/// </remarks>
public static Type GetOwnerType(DependencyProperty dependencyProperty)
=> dependencyProperty.OwnerType;
Expand Down Expand Up @@ -147,13 +177,15 @@ public static (object? value, DependencyPropertyValuePrecedences precedence) Get
return (valueFromImplicitStyle, DependencyPropertyValuePrecedences.ImplicitStyle);
}

if (obj is IDependencyObjectStoreProvider { Store: { } store } && store.GetPropertyDetails(dependencyProperty) is { } details)
if (obj is IDependencyObjectStoreProvider { Store: { } store })
{
var details = store.GetPropertyDetails(dependencyProperty);

// 3rd: Check inherited value
var inheritedValue = details.GetInheritedValue();
if (inheritedValue != DependencyProperty.UnsetValue)
{
return (details.GetInheritedValue(), DependencyPropertyValuePrecedences.Inheritance);
return (inheritedValue, DependencyPropertyValuePrecedences.Inheritance);
}

// 4th: Check default value
Expand All @@ -164,9 +196,8 @@ public static (object? value, DependencyPropertyValuePrecedences precedence) Get
}
}

// 5th: Return default value of the type (should not happen)
var propertyType = dependencyProperty.Type;
return (propertyType.IsValueType ? Activator.CreateInstance(propertyType) : null, DependencyPropertyValuePrecedences.DefaultValue);
// 5th: Return default value of the DP (should not happen)
return (dependencyProperty.GetDefaultValue(obj, obj.GetType()), DependencyPropertyValuePrecedences.DefaultValue);
}

/// <summary>
Expand All @@ -186,24 +217,20 @@ public static void SetValueForPrecedence(
/// Get if the property value is inherited through the visual tree.
/// </summary>
public static bool GetIsInherited(DependencyProperty dependencyProperty)
=> dependencyProperty.GetMetadata(dependencyProperty.OwnerType) is FrameworkPropertyMetadata metadata
&& metadata.Options.HasFlag(FrameworkPropertyMetadataOptions.Inherits);
=> dependencyProperty.IsInherited;

/// <summary>
/// Get the multiple aspects of a given property at the same time.
/// </summary>
public static (Type ValueType, Type OwnerType, string Name, bool IsTypeNullable, bool IsAttached, bool IsInherited, object? defaultValue) GetDetails(
public static (Type PropertyType, Type OwnerType, string Name, bool IsTypeNullable, bool IsAttached, bool IsInherited, object? defaultValue) GetDetails(
DependencyProperty property)
{
var propertyMetadata = property.GetMetadata(property.OwnerType);

return (property.Type,
property.OwnerType,
property.Name,
property.IsTypeNullable,
property.IsAttached,
propertyMetadata is FrameworkPropertyMetadata metadata &&
metadata.Options.HasFlag(FrameworkPropertyMetadataOptions.Inherits),
propertyMetadata?.DefaultValue);
property.IsInherited,
property.GetDefaultValue(referenceObject: null, property.Type));
}
}

0 comments on commit 3bae203

Please sign in to comment.