The following code works with .NET 8.0 CoreCLR, but throws with Mono:
Program.cs:
usingSystem.Reflection;publicclassP{publicstaticvoidMain(){varpropi=typeof(P).GetProperty("Foo");varpi=newRetrofit.PropertyAsParameterInfo(propi!);IEnumerable<Attribute>cattrs=pi.GetCustomAttributes();Console.WriteLine($"Got {cattrs.Count()} attributes");foreach(varcattrincattrs){Console.WriteLine(cattr);}}[Flarg][Blarg]publicintFoo{get;set;}// public static void Foo([Flarg][Blarg]int i) {}}[AttributeUsage(AttributeTargets.Parameter|AttributeTargets.Property)]publicclassFlargAttribute:Attribute{}[AttributeUsage(AttributeTargets.Parameter|AttributeTargets.Property)]publicclassBlargAttribute:Attribute{}PropertyAsParameterInfo.cs:
usingSystem.Reflection;usingSystem.Diagnostics;usingSystem.Diagnostics.CodeAnalysis;usingSystem.Runtime.CompilerServices;namespaceRetrofit;internalsealedclassPropertyAsParameterInfo:ParameterInfo{privatereadonlyPropertyInfo_underlyingProperty;privatereadonlyParameterInfo?_constructionParameterInfo;publicPropertyAsParameterInfo(PropertyInfopropertyInfo){Debug.Assert(propertyInfo!=null,"PropertyInfo must be provided.");AttrsImpl=(ParameterAttributes)propertyInfo.Attributes;NameImpl=propertyInfo.Name;MemberImpl=propertyInfo;ClassImpl=propertyInfo.PropertyType;// It is not a real parameter in the delegate, so,// not defining a real position.PositionImpl=-1;_underlyingProperty=propertyInfo;}publicoverrideboolHasDefaultValue=>_constructionParameterInfois not null&&_constructionParameterInfo.HasDefaultValue;publicoverrideobject?DefaultValue=>_constructionParameterInfo?.DefaultValue;publicoverrideintMetadataToken=>_underlyingProperty.MetadataToken;publicoverrideobject?RawDefaultValue=>_constructionParameterInfo?.RawDefaultValue;publicoverrideobject[]GetCustomAttributes(TypeattributeType,boolinherit){varconstructorAttributes=_constructionParameterInfo?.GetCustomAttributes(attributeType,inherit);if(constructorAttributes==null||constructorAttributesis{Length:0}){return_underlyingProperty.GetCustomAttributes(attributeType,inherit);}varpropertyAttributes=_underlyingProperty.GetCustomAttributes(attributeType,inherit);varmergedAttributes=newAttribute[constructorAttributes.Length+propertyAttributes.Length];Array.Copy(constructorAttributes,mergedAttributes,constructorAttributes.Length);Array.Copy(propertyAttributes,0,mergedAttributes,constructorAttributes.Length,propertyAttributes.Length);returnmergedAttributes;}publicoverrideobject[]GetCustomAttributes(boolinherit){varconstructorAttributes=_constructionParameterInfo?.GetCustomAttributes(inherit);if(constructorAttributes==null||constructorAttributesis{Length:0}){return_underlyingProperty.GetCustomAttributes(inherit);}varpropertyAttributes=_underlyingProperty.GetCustomAttributes(inherit);// Since the constructors attributes should take priority we will add them first,// as we usually call it as First() or FirstOrDefault() in the argument creationvarmergedAttributes=newobject[constructorAttributes.Length+propertyAttributes.Length];Array.Copy(constructorAttributes,mergedAttributes,constructorAttributes.Length);Array.Copy(propertyAttributes,0,mergedAttributes,constructorAttributes.Length,propertyAttributes.Length);returnmergedAttributes;}publicoverrideIList<CustomAttributeData>GetCustomAttributesData(){varattributes=newList<CustomAttributeData>(_constructionParameterInfo?.GetCustomAttributesData()??Array.Empty<CustomAttributeData>());attributes.AddRange(_underlyingProperty.GetCustomAttributesData());returnattributes.AsReadOnly();}publicoverrideType[]GetOptionalCustomModifiers()=>_underlyingProperty.GetOptionalCustomModifiers();publicoverrideType[]GetRequiredCustomModifiers()=>_underlyingProperty.GetRequiredCustomModifiers();publicoverrideboolIsDefined(TypeattributeType,boolinherit){return(_constructionParameterInfois not null&&_constructionParameterInfo.IsDefined(attributeType,inherit))||_underlyingProperty.IsDefined(attributeType,inherit);}}repro.csproj:
<ProjectSdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroupCondition="false">
<UseMonoRuntime>true</UseMonoRuntime>
<SelfContained>true</SelfContained>
</PropertyGroup>
</Project>
Expected output:
$ dotnet runGot 2 attributesFlargAttributeBlargAttribute
Actual output
$ dotnet runUnhandled Exception:System.ArgumentNullException: Value cannot be null. (Parameter 'attributeType') at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Type attributeType, Boolean inherit) at System.Reflection.RuntimePropertyInfo.GetCustomAttributes(Type attributeType, Boolean inherit) at Retrofit.PropertyAsParameterInfo.GetCustomAttributes(Type attributeType, Boolean inherit) in /private/tmp/parma/PropertyAsParameterInfo.cs:line 42 at System.Reflection.CustomAttribute.GetCustomAttributesBase(ICustomAttributeProvider obj, Type attributeType, Boolean inheritedOnly) at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Type attributeType, Boolean inherit) at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Boolean inherit) at System.Attribute.GetCustomAttributes(ParameterInfo element) at System.Reflection.CustomAttributeExtensions.GetCustomAttributes(ParameterInfo element) at P.Main() in /private/tmp/parma/Program.cs:line 9[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentNullException: Value cannot be null. (Parameter 'attributeType') at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Type attributeType, Boolean inherit) at System.Reflection.RuntimePropertyInfo.GetCustomAttributes(Type attributeType, Boolean inherit) at Retrofit.PropertyAsParameterInfo.GetCustomAttributes(Type attributeType, Boolean inherit) in /private/tmp/parma/PropertyAsParameterInfo.cs:line 42 at System.Reflection.CustomAttribute.GetCustomAttributesBase(ICustomAttributeProvider obj, Type attributeType, Boolean inheritedOnly) at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Type attributeType, Boolean inherit) at System.Reflection.CustomAttribute.GetCustomAttributes(ICustomAttributeProvider obj, Boolean inherit) at System.Attribute.GetCustomAttributes(ParameterInfo element) at System.Reflection.CustomAttributeExtensions.GetCustomAttributes(ParameterInfo element) at P.Main() in /private/tmp/parma/Program.cs:line 9
The following code works with .NET 8.0 CoreCLR, but throws with Mono:
Program.cs:PropertyAsParameterInfo.cs:repro.csproj:Expected output:
Actual output