Description
DefaultValueAttribute.Value throws on access (due to #100416) when System.ComponentModel.DefaultValueAttribute.IsSupported switch is false and it breaks XmlSerializer and other serializers/reflection. But it's very common to use not (Type, string) overload, but 1 arg primitive which do not use TypeDescriptor API family.
Reproduction Steps
using System.ComponentModel;
using System.Xml.Serialization;
// _ = typeof(C).GetProperty("i")!.GetCustomAttribute<DefaultValueAttribute>()!.Value;
XmlSerializer serializer = new(typeof(C));
public class C { [DefaultValue(5)] public int i {get; set;} }
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<RuntimeHostConfigurationOption
Include="System.ComponentModel.DefaultValueAttribute.IsSupported"
Value="false" Trim="true" />
</ItemGroup>
</Project>
Expected behavior
No exception, use constructor arg as is.
Actual behavior
Unhandled exception. System.InvalidOperationException: There was an error reflecting type 'C'.
---> System.ArgumentException: Runtime instantiation of this attribute is not allowed.
at System.ComponentModel.DefaultValueAttribute.get_Value()
at System.Xml.Serialization.XmlAttributes..ctor(ICustomAttributeProvider provider)
at System.Xml.Serialization.XmlReflectionImporter.GetAttributes(MemberInfo memberInfo)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at Program.<Main>$(String[] args) in C:\Source\ttt\Program.cs:line 4
Workaround
set _value to some sentinel if TypeDescriptor is required and throw only in this case.
Description
DefaultValueAttribute.Valuethrows on access (due to #100416) whenSystem.ComponentModel.DefaultValueAttribute.IsSupportedswitch isfalseand it breaksXmlSerializerand other serializers/reflection. But it's very common to use not(Type, string)overload, but 1 arg primitive which do not useTypeDescriptorAPI family.Reproduction Steps
Expected behavior
No exception, use constructor arg as is.
Actual behavior
Workaround
set
_valueto some sentinel ifTypeDescriptoris required and throw only in this case.