Thank you Jb, this information is very useful However I did exactly what you said, same steps, and I've almost the same problem, PeVerify fails with this message: [MD]: Error: Signature contains long form (such as ELEMENT_TYPE_CLASS<token of System.String>). [token:0x1B000002]
If i use a class defined in the same assembly instead "int", everything works ok. One of the things i noticed, is that when i read genericArgument is "System.Int32" but the Module property is "MyAssembly.dll", is that ok? should not be something like "mscorlib" or CommonLanguageRuntimeLibrary... Thank you again. 2011/1/20 Jb Evain <[email protected]> > Hey, > > On Thu, Jan 20, 2011 at 11:51 PM, José F. Romaniello > <[email protected]> wrote: > > ok, i have an assembly "A" just with these three things: > > //interface for template > > public interface IFoo<T> > > { > > } > > //template > > public class Foo<T> : IFoo<T> > > {} > > //target > > [ExtendWith(typeof(Foo<int>))] > > public class Target > > { > > } > > From another assembly "B", I am trying to modify this one, in order to > > make Target implement IFoo<int> (just that for now). > > So, i look all types that has the ExtendWith attribute, and then i read > the > > constructor arguments and i get a GenericInstanceType pointing to > Foo<int> > > and i have the Type Definition of Target. > > So, what is the best way to get IFoo<int> from the GenericInstanceType? > > If i do genericInstanceType.Resolve().Interfaces <- these generic > instance > > types doesn't have the arguments... > > So first of all, you need to take a few things into account. In one > assembly, you can get a generic instance of a type, without having all > the details of a type, that is, if the type is defined in another > assembly. > > If you have GenericInstanceType, you usually use .ElementType to > figure out the type which is instantiated. If you use .Resolve(), it > will return the definition of the ElementType. Which means that it may > have to go look for it in another assembly. > > And with Cecil, you can't directly use types defined in a module into > another module. You have to create references. > > So in your scenario, if IFoo<T> is in IFoo.dll, if Foo<T> is is > Foo.dll, and Target in Target.dll, you have to take care of a few > things. > > When you have the TypeDefinition `Target`, and that you get its custom > attribute, you'll get a TypeReference to Foo`1 (in that case, a > GenericInstanceType with the ElementType being Foo`1 and with a > generic argument being a reference to int32. > > If you Resolve this reference, it will open Foo.dll and get you the > TypeDefinition of Foo`1. > If you browse its interfaces, you'll have a TypeReference to IFoo`1 . > If you Resolve this reference, it will open IFoo.dll and get you the > TypeDefinition of IFoo`1. > > So now we're all down the chain, and you want to make Target implement > IFoo`1 with the generic arguments of the GenericInterfaceType in the > CustomAttribute. > > You can't just add the interface, you have to create the proper references. > > ModuleDefinition targetModule = ...; > TypeDefinition targetType = ...; > GenericInstanceType foo_of_int_ref = (GenericInstanceType) > targetType.CustomAttributes [0].ConstructorArguments [0]; > TypeReference foo_of_t_ref = foo_of_int_ref.ElementType; > > TypeDefinition foo_of_t = foo_of_t_ref.Resolve (); // opens Foo.dll, > foo_of_t.Module is Foo.dll > TypeReference ifoo_of_t_ref = foo_of_t.Interfaces [0]; > > TypeDefinition ifoo_of_t = ifoo_of_t_ref.Resolve (); // opens > IFoo.dll, ifoo_of_t.Module is IFoo.dll > > So now, let's make targetType implement IFoo with the arguments passed to > Foo. > > TypeReference ifoo_ref_in_target = targetModule.Import (ifoo_of_t); > GenericInstanceType ifoo_instance_in_target = new GenericInstanceType > (ifoo_ref_in_target); > > foreach (TypeReference argument in foo_of_int_ref) > ifoo_instance_in_target.GenericArguments.Add (argument); > > targetType.Interfaces.Add (ifoo_instance_in_target); > > And here we are. The important thing here is to get a proper reference > (import) for IFoo for the target module. Of course the code above is a > bit long and you cant short circuit a few things, but it helps > remembering all the different steps that need to happen. > > Also note that in the loop: > > foreach (TypeReference argument in foo_of_int_ref) > ifoo_instance_in_target.GenericArguments.Add (argument); > > We can re-use the argument as they are, because they are already > scoped for the targetModule, after all, the original Foo<int> > instantiation is declared in targetModule, so we don't need to create > a proper reference for them. > > Jb > > -- > -- > mono-cecil -- -- mono-cecil
