I am currently implementing a type name resolution scheme. The available information is very similar to what you would get in a regular C# source project:
- a list of
Assembly
references - a list of
using
namespaces
At runtime, for each type name to resolve, the name is either fully qualified (with namespace, but not with assembly name) or it is a simple name that is expected to come from one of the using
namespaces.
In order to find the Type
matching each identifier, I am considering one of two strategies:
Preload all assemblies using
Assembly.Load
and scan all types. All simple names that have a namespace prefix matching one of theusing
namespaces will be precached. Also a dictionary is created mapping each namespace qualified type name in the assembly directly to itsType
. Conflict resolution will be performed accordingly during the loading phase.Do not preload anything. Whenever a type name arrives, try the following sequence:
Assume the name is fully qualified; concatenate each of the referenced assembly names in turn to create an assembly-qualified name and call
Type.GetType
to see if we get a valid type.If the above step does not produce any valid type and the name has no prefix, assume it is a simple name; repeat the above step but each time prepend the simple name with one of the
using
namespaces to see if we get a valid type.
Which approach would be preferable and what are the pros and cons?
It is unclear at the moment how many types will need to be resolved in this way for every run but I'm assuming anything between 10 and 100. Multiple assemblies can be referenced at any point, each with potentially hundreds of types.
I am interested in knowing the relative performances of both strategies and curious to hear about existing best practices to deal with this scenario. In addition to performance, it would be very helpful to understand any difference in behavior side-effects: for instance, does scanning all types in an Assembly
execute all the static constructors for loaded types? I would prefer an approach that would be as lazy as possible in running any code from referenced assemblies.
In the new .NET Standard it turns out there is a much better way to do it, by using the new
System.Reflection.Metadata
namespace. In their own words:Here's a small code snippet for listing the name and namespace for all type definitions in a given assembly file: