Search code examples
c#.netcilsystem.reflection.metadata

Getting interface nullable context metadata from System.Reflection.Metadata in C# 8


I am making a tool to handle new C# 8 nullable contexts at the moment. Basically a API approval tool for my projects.

I am using System.Reflection.Metadata, just having problem extracting metadata in one case.

public class DerivedNullableBase2 : MyBase<MyBase<string?>?>
{
}

I am attempting to get the C#8 the nullable context for a API generator tool I am creating. So for the above class the following IL is generated:

.class auto ansi nested public beforefieldinit DerivedNullableInterface2
       extends [netstandard]System.Object
       implements class [netstandard]System.Collections.Generic.IEnumerable`1<class [netstandard]System.Collections.Generic.IEnumerable`1<string>>,
                  [netstandard]System.Collections.IEnumerable
{
  .interfaceimpl type class [netstandard]System.Collections.Generic.IEnumerable`1<class [netstandard]System.Collections.Generic.IEnumerable`1<string>>
  .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8[]) = ( 01 00 03 00 00 00 00 00 02 00 00 ) 
} // end of class DerivedNullableInterface2

I want to extract the NullableAttribute contained within to determine the nullable context of the generic interfaces.

I attempted to get the attribute both via the TypeDefinition and the InterfaceImplementation but doesn't appear to be there, how would I extract that NullableAttribute in this scenario?


Solution

  • The following code will extract a NullableAttribute from a InterfaceImplementation using C# 8 syntax.

    using var peReader = new PEReader(File.OpenRead(Assembly.GetExecutingAssembly().Location));
    var mdReader = peReader.GetMetadataReader();
    
    foreach (var attributeHandle in mdReader.CustomAttributes)
    {
        var attribute = mdReader.GetCustomAttribute(attributeHandle);
        var ctorHandle = attribute.Constructor;
    
        EntityHandle attributeTypeHandle = ctorHandle.Kind switch
        {
            HandleKind.MethodDefinition => mdReader.GetMethodDefinition((MethodDefinitionHandle)ctorHandle).GetDeclaringType(),
            HandleKind.MemberReference => mdReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent,
            _ => throw new InvalidOperationException(),
        };
    
        StringHandle attributeTypeNameHandle = attributeTypeHandle.Kind switch
        {
            HandleKind.TypeDefinition => mdReader.GetTypeDefinition((TypeDefinitionHandle)attributeTypeHandle).Name,
            HandleKind.TypeReference => mdReader.GetTypeReference((TypeReferenceHandle)attributeTypeHandle).Name,
            _ => throw new InvalidOperationException(),
        };
    
        if (mdReader.StringComparer.Equals(attributeTypeNameHandle, "NullableAttribute"))
        {
            Console.WriteLine(attribute.Parent.Kind);
        }
    }
    

    This was provided by https://github.com/dotnet/corefx/issues/40234#issuecomment-520254880