Runtime: [question] System.Reflection.Metadata how to "resolve" a TypeReference?

Created on 6 Mar 2019  路  3Comments  路  Source: dotnet/runtime

Let's say I have:

  • Assembly Foo.dll with class Bar: public class Bar { }

If I grab Bar's TypeDefinition and look at BaseType:

//BaseType should be System.Object
var h = (TypeReferenceHandle)typeDefinition.BaseType;
var typeReference = reader.GetTypeReference (h);

If I want to get the TypeDefinition for System.Object here, I have to:

  • Get a MetadataReader for mscorlib.dll (that part is easy)
  • Loop over all the reader.TypeDefinitions and compare the full name...

If I need to do this a lot, such as a case of traversing base types... Is the only efficient way here to maintain my own mapping (or cache) of TypeDefinition and look them up for subsequent calls? Is there a better way to look up a TypeDefinition given the type's full name?

Mono.Cecil has a ResolveType() method that gives you a TypeDefinition from a TypeReference. It is a very different API, in general, though: https://github.com/jbevain/cecil/blob/1b79b96d29f1e8e9ba832191b1b42ea9cb750d20/Mono.Cecil/MetadataResolver.cs#L131-L154

Mono.Cecil uses "exported types" to look up TypeDefinition, but using SRM, reader.ExportedTypes.Count has been 0 for any assembly I've opened.

Any suggestions welcome!

area-System.Reflection.Metadata question

Most helpful comment

So this NuGet package is exactly what I'm looking for: https://www.nuget.org/packages/System.Reflection.MetadataLoadContext

This example is basically what we need to do:

var resolver = new PathAssemblyResolver (new [] {
    assembly.Location,
    typeof (object).Assembly.Location,
});
using (var context = new MetadataLoadContext (resolver)) {
    var assembly = context.LoadFromAssemblyName (assemblyName.Name);
    var type = assembly.GetType (typeName);
    Assert.AreEqual ("System.Object", type.BaseType.FullName);
}

These APIs will be much easier to work with than using SRM directly.

Thanks!

All 3 comments

System.Reflection.Metadata is a low level component. It does not resolve type references. The components that build on top of System.Reflection.Metadata are responsible for resolving type references.

You may want to take a look at https://github.com/dotnet/corefx/tree/master/src/System.Reflection.MetadataLoadContext . This is higher level component that provides the familiar reflection object model on top of System.Reflection.Metadata, including resolving type references. More details in https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#type-metadataloadcontext

Re ExportedTypes: please refer to ECMA 335 specification:

22.14 ExportedType : 0x27 The ExportedType table holds a row for each type:

a. _Defined within other modules of this Assembly_; that is exported out of this Assembly. In essence, it stores TypeDef row numbers of all types that are marked public in other modules that this Assembly comprises. The actual target row in a TypeDef table is given by the combination of TypeDefId (in effect, row number) and Implementation (in effect, the module that holds the target TypeDef table). Note that this is the only occurrence in metadata of foreign tokens; that is, token values that have a meaning in another module. (A regular token value is an index into a table in the current module); OR

b. _Originally defined in this Assembly but now moved to another Assembly_. Flags must have IsTypeForwarder set and Implementation is an AssemblyRef indicating the Assembly the type may now be found in.

So this NuGet package is exactly what I'm looking for: https://www.nuget.org/packages/System.Reflection.MetadataLoadContext

This example is basically what we need to do:

var resolver = new PathAssemblyResolver (new [] {
    assembly.Location,
    typeof (object).Assembly.Location,
});
using (var context = new MetadataLoadContext (resolver)) {
    var assembly = context.LoadFromAssemblyName (assemblyName.Name);
    var type = assembly.GetType (typeName);
    Assert.AreEqual ("System.Object", type.BaseType.FullName);
}

These APIs will be much easier to work with than using SRM directly.

Thanks!

Was this page helpful?
0 / 5 - 0 ratings