Mixing CCI and reflection

Topics: Metadata Model
Aug 7, 2009 at 3:14 AM

Hopefully I'm not being too annoying here with all these questions... :)

Is there a relatively straightforward way to map between CCI and Reflection models of an assembly?

More specifically, one of the things that I'm trying to do at the moment is to walk through an assembly (which I don't want to load via Reflection, and may end up mutating later on) and discover instances of a particular set of custom attributes, defined in another assembly.  That second assembly is being loaded into both CCI and the host app (so is accessible via reflection).

I've got code which can find the elements that have the attributes applied to them (although the lookup is a bit messy; it uses UnitHelper.AssembliesAreEquivalent and TypeHelper.GetDefiningUnitReference to ask "is this attribute defined in the attribute assembly?").  That much seems to be working fine.

What I'd really like though is some way to take the ICustomAttribute and produce an actual concrete instance of the attribute (ie. invoke the constructor and provide it with the equivalent parameters from the metadata).  Given that the "real" assembly is already loaded, it seems like it ought to be possible.  I'm hoping that there's an easier/better way than looking up each element individually by name with the reflection APIs, though.

(I want to get a "real" attribute because I can query its properties much easier that way.)

 

And on a related note, given a MetadataReaderHost with the required assemblies loaded into it, and a Type, is there a quick way to get to the corresponding ITypeDefinition?  I've found this:

 

UnitHelper.FindType(host.NameTable, host.FindAssembly(UnitHelper.GetAssemblyIdentity(type.Assembly.GetName(), host)), type.FullName)

which looks like it ought to work (though I haven't tried it yet).  Seems a bit long-winded though (but I guess I could always just create my own helper functions to shorten it).  Is there a better way?

Coordinator
Aug 7, 2009 at 3:48 PM

There is not much support for mapping between CCI and System.Reflection. There are some security implications, so it may be best to create a new assembly, say ReflectionBridge, that includes all of this mapping ability.

UnitHelper.FindType is of somewhat limited usefulness since it does not deal with name mangling for generic types and it expects C# like formatting, not Reflection like formatting. Also, it seems slow and wastefull to serialize the Reflection type into a string and then parse it in order to find the corresponding CCI type. You'd only do that if you're starting out with a string in the first place.

This seems like a good time for the open source nature of CCI to go from "Herman does all the coding" to lets all contribute... ;-)

Aug 8, 2009 at 9:58 AM

On that note (starting out with a string in the first place)...

One of the parameters of the attribute that I'm looking for is a Type.  This seems to come out of CCI as an IMetadataTypeof, which in turn provides an ITypeReference, which is great.  (And a bit surprising; I always thought that attributes were instantiated and serialised at compile time, rather than storing constructor & arguments for later invocation.  Guess I never really looked into it too hard.)

However, I'd like to follow the established pattern of standard framework attributes and permit the AssemblyQualifiedName of the type to be specified instead (thereby removing the requirement for an assembly reference).  This comes out as an IMetadataConstant string, which is all reasonable.

The tricky bit is that I want to synthesise an ITypeReference from that string when the assembly is processed, to simplify later operations.  At this point, I don't want to resolve the reference (ie. I don't want to make it load the referenced assembly).  So as far as I can tell I can't use any of the existing implementations of ITypeReference, and will have to create my own type instead.  Is that correct?

(I have code which gets an AssemblyIdentity and a full typename from the string [which in turn is assumed to be structured like Type.AssemblyQualifiedName returns, ie. reflection style].  But other than creating my own somehow, I'm not sure how to turn that into an ITypeReference.)

Coordinator
Aug 8, 2009 at 6:06 PM

The short answer is that you're going to have to write some code here. Much of the logic you want is already present as internal implementation details of the PeReader assembly. See the code in Attributes.cs.

This would be useful functionality to have in the "ReflecionBridge" assembly. Hint, hint.