using System; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; [MyAttribute<int>("hi", NamedProp = 3)] public class C { static void Main() { foreach (Attribute a in typeof(C).GetCustomAttributesAllowGeneric()) { Console.WriteLine(a); } } } [AttributeUsage(AttributeTargets.Class)] public class MyAttribute<T>(string arg) : Attribute { public T NamedProp { get; set; } public override string ToString() => $"{arg} {NamedProp}"; } internal static class Utility { internal static IEnumerable<Attribute> GetCustomAttributesAllowGeneric(this MemberInfo member) { using PEReader peReader = new PEReader(File.OpenRead(member.Module.Assembly.Location)); MetadataReader mdReader = peReader.GetMetadataReader(); EntityHandle attributedMemberHandle = MetadataTokens.EntityHandle(member.MetadataToken); foreach (CustomAttributeHandle cah in mdReader.GetCustomAttributes(attributedMemberHandle)) { CustomAttribute att = mdReader.GetCustomAttribute(cah); int attCtorToken = MetadataTokens.GetToken(att.Constructor); Type constructedAttributeType; switch (att.Constructor.Kind) { case HandleKind.MemberReference: MemberReference mr = mdReader.GetMemberReference((MemberReferenceHandle)att.Constructor); MethodSignature<Type> sig = mr.DecodeMethodSignature(SignatureTypeProvider.Instance, new GenericContext()); switch (mr.Parent.Kind) { case HandleKind.TypeSpecification: TypeSpecification attTypeSpec = mdReader.GetTypeSpecification((TypeSpecificationHandle)mr.Parent); constructedAttributeType = attTypeSpec.DecodeSignature(SignatureTypeProvider.Instance, default); break; default: throw new NotSupportedException(); } break; case HandleKind.MethodDefinition: MethodDefinition attCtor = mdReader.GetMethodDefinition((MethodDefinitionHandle)att.Constructor); TypeDefinition attClass = mdReader.GetTypeDefinition(attCtor.GetDeclaringType()); Console.WriteLine(mdReader.GetString(attClass.Name)); throw new NotImplementedException(); break; default: throw new NotSupportedException(); } CustomAttributeValue<Type> attValue = att.DecodeValue(CustomAttributeTypeProvider.Instance); ConstructorInfo attCtorInfo = (ConstructorInfo)constructedAttributeType.Module.ResolveMethod(attCtorToken); Attribute attObject = (Attribute)attCtorInfo.Invoke(GetAttributeConstructorArguments(attValue)); // Set properties foreach (CustomAttributeNamedArgument<Type> namedArg in attValue.NamedArguments) { PropertyInfo prop = constructedAttributeType.GetProperty(namedArg.Name); prop.SetValue(attObject, namedArg.Value); } yield return attObject; } } private static object?[] GetAttributeConstructorArguments(CustomAttributeValue<Type> attValue) { object?[] args = new object[attValue.FixedArguments.Length]; for (int i = 0; i < attValue.FixedArguments.Length; i++) { CustomAttributeTypedArgument<Type> arg = attValue.FixedArguments[i]; args[i] = arg.Value; } return args; } }