Add TypeConverter fallback to DefaultValueAttribute (dotnet/coreclr#19354)
authorMarco Rossignoli <marco.rossignoli@gmail.com>
Wed, 15 Aug 2018 01:56:43 +0000 (03:56 +0200)
committerJan Kotas <jkotas@microsoft.com>
Wed, 15 Aug 2018 01:56:43 +0000 (18:56 -0700)
Commit migrated from https://github.com/dotnet/coreclr/commit/431d041b7697a7ce307caa6090fab01ffd7ae652

src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs

index 3cdc907..5f7108a 100644 (file)
@@ -2,11 +2,8 @@
 // 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;
-using System.ComponentModel;
-using System.Diagnostics;
 using System.Globalization;
-using System.Runtime.InteropServices;
+using System.Threading;
 
 namespace System.ComponentModel
 {
@@ -23,6 +20,9 @@ namespace System.ComponentModel
         /// </devdoc>
         private object _value;
 
+        // Delegate ad hoc created 'TypeDescriptor.ConvertFromInvariantString' reflection object cache
+        static object s_convertFromInvariantString;
+
         /// <devdoc>
         /// <para>Initializes a new instance of the <see cref='System.ComponentModel.DefaultValueAttribute'/> class, converting the
         ///    specified value to the
@@ -36,7 +36,11 @@ namespace System.ComponentModel
             // load an otherwise normal class.
             try
             {
-                if (type.IsSubclassOf(typeof(Enum)))
+                if (TryConvertFromInvariantString(type, value, out object convertedValue))
+                {
+                    _value = convertedValue;
+                }
+                else if (type.IsSubclassOf(typeof(Enum)))
                 {
                     _value = Enum.Parse(type, value, true);
                 }
@@ -48,6 +52,28 @@ namespace System.ComponentModel
                 {
                     _value = Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
                 }
+
+                return;
+
+                // Looking for ad hoc created TypeDescriptor.ConvertFromInvariantString(Type, string)
+                bool TryConvertFromInvariantString(Type typeToConvert, string stringValue, out object conversionResult)
+                {
+                    conversionResult = null;
+
+                    // lazy init reflection objects
+                    if (s_convertFromInvariantString == null)
+                    {
+                        Type typeDescriptorType = Type.GetType("System.ComponentModel.TypeDescriptor, System.ComponentModel.TypeConverter", throwOnError: false);
+                        Volatile.Write(ref s_convertFromInvariantString, typeDescriptorType == null ? new object() : Delegate.CreateDelegate(typeof(Func<Type, string, object>), typeDescriptorType, "ConvertFromInvariantString", ignoreCase: false));
+                    }
+
+                    if (!(s_convertFromInvariantString is Func<Type, string, object> convertFromInvariantString))
+                        return false;
+
+                    conversionResult = convertFromInvariantString(typeToConvert, stringValue);
+
+                    return true;
+                }
             }
             catch
             {