diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlObjectCreationFactory.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlObjectCreationFactory.cs new file mode 100644 index 000000000..c9631dcac --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlObjectCreationFactory.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; + +namespace System.Xaml.Schema +{ + public static class XamlObjectCreationFactory + { + public static void RegisterCreator(Func creator) + { + if (creator == null) throw new ArgumentNullException(nameof(creator)); + RegisterCreator(typeof(T), () => creator()); + } + + public static void RegisterCreator(Type type, Func creator) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + s_xamlObjectCreatorDictionary[type] = creator ?? throw new ArgumentNullException(nameof(creator)); + + HasBeenRegister = true; + } + + public static void RegisterTypeCreator(Func> typeCreator) + { + _typeCreator = typeCreator; + HasBeenRegister = true; + } + + internal static bool HasBeenRegister { get; private set; } + + private static Func> _typeCreator; + + internal static bool TryGetCreator(Type type, out Func creator) + { + if (_typeCreator != null) + { + creator = _typeCreator(type); + if (creator != null) + { + return true; + } + } + + return s_xamlObjectCreatorDictionary.TryGetValue(type, out creator); + } + + private static readonly ConcurrentDictionary> s_xamlObjectCreatorDictionary = + new ConcurrentDictionary>(); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlTypeInvoker.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlTypeInvoker.cs index 7eedd71a9..f5988c86f 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlTypeInvoker.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/Schema/XamlTypeInvoker.cs @@ -21,7 +21,7 @@ public class XamlTypeInvoker internal MethodInfo EnumeratorMethod { get; set; } private XamlType _xamlType; - private Action _constructorDelegate; + private Func _instanceCreatorDelegate; private ThreeValuedBool _isPublic; @@ -290,20 +290,13 @@ public static object CreateInstance(XamlTypeInvoker type) { return null; } - object inst = CallCtorDelegate(type); + object inst = type._instanceCreatorDelegate(); return inst; } #if TARGETTING35SP1 #else #endif - private static object CallCtorDelegate(XamlTypeInvoker type) - { - object inst = FormatterServices.GetUninitializedObject(type._xamlType.UnderlyingType); - InvokeDelegate(type._constructorDelegate, inst); - return inst; - } - private static void InvokeDelegate(Action action, object argument) { action.Invoke(argument); @@ -315,10 +308,21 @@ private static void InvokeDelegate(Action action, object argument) // returns true if a delegate is available, false if not private static bool EnsureConstructorDelegate(XamlTypeInvoker type) { - if (type._constructorDelegate != null) + if (type._instanceCreatorDelegate != null) { return true; } + Type underlyingType = null; + if (XamlObjectCreationFactory.HasBeenRegister) + { + underlyingType = type._xamlType.UnderlyingType.UnderlyingSystemType; + if (XamlObjectCreationFactory.TryGetCreator(underlyingType, out Func creator)) + { + type._instanceCreatorDelegate = creator; + return true; + } + } + if (!type.IsPublic) { return false; @@ -333,7 +337,8 @@ private static bool EnsureConstructorDelegate(XamlTypeInvoker type) return false; } - Type underlyingType = type._xamlType.UnderlyingType.UnderlyingSystemType; + underlyingType ??= type._xamlType.UnderlyingType.UnderlyingSystemType; + // Look up public ctors only, for equivalence with Activator.CreateInstance ConstructorInfo tConstInfo = underlyingType.GetConstructor(Type.EmptyTypes); if (tConstInfo == null) @@ -352,9 +357,14 @@ private static bool EnsureConstructorDelegate(XamlTypeInvoker type) } IntPtr constPtr = tConstInfo.MethodHandle.GetFunctionPointer(); // This requires Reflection Permission - Action ctorDelegate = ctorDelegate = + Action ctorDelegate = (Action)s_actionCtor.Invoke(new object[] { null, constPtr }); - type._constructorDelegate = ctorDelegate; + type._instanceCreatorDelegate = () => + { + object inst = FormatterServices.GetUninitializedObject(type._xamlType.UnderlyingType); + InvokeDelegate(ctorDelegate, inst); + return inst; + }; return true; } } diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/ref/System.Xaml.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/ref/System.Xaml.cs index 33151bf7c..05d2c4530 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/ref/System.Xaml.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/ref/System.Xaml.cs @@ -1106,4 +1106,11 @@ public XamlValueConverter(System.Type converterType, System.Xaml.XamlType target public static bool operator !=(System.Xaml.Schema.XamlValueConverter converter1, System.Xaml.Schema.XamlValueConverter converter2) { throw null; } public override string ToString() { throw null; } } + + public static class XamlObjectCreationFactory + { + public static void RegisterCreator(Func creator) { } + public static void RegisterCreator(Type type, Func creator) { } + public static void RegisterTypeCreator(Func> typeCreator) { } + } }