Let's say I have:
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:
MetadataReader for mscorlib.dll (that part is easy)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!
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!
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:
These APIs will be much easier to work with than using SRM directly.
Thanks!