// 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.Globalization; using System.Reflection; using System.Threading; namespace System.ComponentModel { /// /// Specifies the default value for a property. /// [AttributeUsage(AttributeTargets.All)] public class DefaultValueAttribute : Attribute { /// /// This is the default value. /// private object? _value; // Delegate ad hoc created 'TypeDescriptor.ConvertFromInvariantString' reflection object cache private static object? s_convertFromInvariantString; /// /// Initializes a new instance of the /// class, converting the specified value to the specified type, and using the U.S. English /// culture as the translation context. /// public DefaultValueAttribute(Type type, string? value) { // The null check and try/catch here are because attributes should never throw exceptions. // We would fail to load an otherwise normal class. if (type == null) { return; } try { if (TryConvertFromInvariantString(type, value, out object? convertedValue)) { _value = convertedValue; } else if (type.IsSubclassOf(typeof(Enum)) && value != null) { _value = Enum.Parse(type, value, true); } else if (type == typeof(TimeSpan) && value != null) { _value = TimeSpan.Parse(value); } else { _value = Convert.ChangeType(value, type, CultureInfo.InvariantCulture); } // Looking for ad hoc created TypeDescriptor.ConvertFromInvariantString(Type, string) static 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); MethodInfo? mi = typeDescriptorType?.GetMethod("ConvertFromInvariantString", BindingFlags.NonPublic | BindingFlags.Static); Volatile.Write(ref s_convertFromInvariantString, mi == null ? new object() : mi.CreateDelegate(typeof(Func))); } if (!(s_convertFromInvariantString is Func convertFromInvariantString)) return false; try { conversionResult = convertFromInvariantString(typeToConvert, stringValue); } catch { return false; } return true; } } catch { } } /// /// Initializes a new instance of the /// class using a Unicode character. /// public DefaultValueAttribute(char value) { _value = value; } /// /// Initializes a new instance of the /// class using an 8-bit unsigned integer. /// public DefaultValueAttribute(byte value) { _value = value; } /// /// Initializes a new instance of the /// class using a 16-bit signed integer. /// public DefaultValueAttribute(short value) { _value = value; } /// /// Initializes a new instance of the /// class using a 32-bit signed integer. /// public DefaultValueAttribute(int value) { _value = value; } /// /// Initializes a new instance of the /// class using a 64-bit signed integer. /// public DefaultValueAttribute(long value) { _value = value; } /// /// Initializes a new instance of the /// class using a single-precision floating point number. /// public DefaultValueAttribute(float value) { _value = value; } /// /// Initializes a new instance of the /// class using a double-precision floating point number. /// public DefaultValueAttribute(double value) { _value = value; } /// /// Initializes a new instance of the /// class using a value. /// public DefaultValueAttribute(bool value) { _value = value; } /// /// Initializes a new instance of the /// class using a . /// public DefaultValueAttribute(string? value) { _value = value; } /// /// Initializes a new instance of the /// class. /// public DefaultValueAttribute(object? value) { _value = value; } /// /// Initializes a new instance of the /// class using a value. /// [CLSCompliant(false)] public DefaultValueAttribute(sbyte value) { _value = value; } /// /// Initializes a new instance of the /// class using a value. /// [CLSCompliant(false)] public DefaultValueAttribute(ushort value) { _value = value; } /// /// Initializes a new instance of the /// class using a value. /// [CLSCompliant(false)] public DefaultValueAttribute(uint value) { _value = value; } /// /// Initializes a new instance of the /// class using a value. /// [CLSCompliant(false)] public DefaultValueAttribute(ulong value) { _value = value; } /// /// Gets the default value of the property this attribute is bound to. /// public virtual object? Value => _value; public override bool Equals(object? obj) { if (obj == this) { return true; } if (!(obj is DefaultValueAttribute other)) { return false; } if (Value == null) { return other.Value == null; } return Value.Equals(other.Value); } public override int GetHashCode() => base.GetHashCode(); protected void SetValue(object? value) => _value = value; } }