-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add TypeConverter fallback to DefaultValueAttribute #19354
Changes from 9 commits
aca9eb3
921b2f5
e2bce7b
c996bfe
304df3e
3909a3c
5075ea8
5d63db2
aee210a
8cae155
3390620
ea79dac
65cb4aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 @@ public class DefaultValueAttribute : Attribute | |
/// </devdoc> | ||
private object _value; | ||
|
||
// Delegate 'TypeDescriptor.InternalConvertFromInvariantString' 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 @@ public DefaultValueAttribute(Type type, string value) | |
// 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,9 +52,39 @@ public DefaultValueAttribute(Type type, string value) | |
{ | ||
_value = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); | ||
} | ||
|
||
return; | ||
|
||
// Looking for object TypeDescriptor.InternalConvertFromInvariantString(Type, string) and call to conversion function ConvertFromInvariantString | ||
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, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should load the type from System.ComponentModel.TypeConverter directly, not from System facade. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because we'll know if TypeConverter exists when we call conversion method and so check could pass but fail after? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. System.dll is .NET Framework compatibility shim. It should not be loaded or pulled unless really necessary System.ComponentModel.TypeConverter is the native .NET Core implementation assembly for this, so it is where we should be loading this from. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahhh i misread...understood i used System... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
Delegate convertFromInvariantString = null; | ||
if (typeDescriptorType != null) | ||
{ | ||
convertFromInvariantString = Delegate.CreateDelegate(typeof(Func<Type, string, object>), typeDescriptorType, "InternalConvertFromInvariantString", ignoreCase: false, throwOnBindFailure: false); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
My fault i wasn't clear, but you answered! If i remove // lazy init reflection objects
if (s_convertFromInvariantString == null)
{
Type typeDescriptorType = Type.GetType("System.ComponentModel.TypeDescriptor, System, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", throwOnError: false);
Volatile.Write(ref s_convertFromInvariantString, typeDescriptorType == null ? new object() : Delegate.CreateDelegate(typeof(Func<Type, string, object>), typeDescriptorType, "InternalConvertFromInvariantString", ignoreCase: false));
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
Volatile.Write(ref s_convertFromInvariantString, convertFromInvariantString ?? new object()); | ||
} | ||
|
||
if (!(s_convertFromInvariantString is Func<Type, string, object> internalConvertFromInvariantString)) | ||
return false; | ||
|
||
conversionResult = internalConvertFromInvariantString(typeToConvert, stringValue); | ||
|
||
return true; | ||
} | ||
} | ||
catch | ||
{ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Unnecessary new line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think we can call the method just
ConvertFromInvariantString
and drop the internal from all the names.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done