Ouch sorry ignore me. CallVirt *does* work with MethodReferences that contain open genericparameter types. There was an error in my unit-tests.
Sorry On Wed, Mar 7, 2012 at 9:00 PM, Hendry Luk <[email protected]> wrote: > That trick works but only up to a certain point. But if your method use > generic arguments, the MakeHostInstanceGeneric helper does not seem to > do the trick. > > For instance: > public class SomeClass<T> > { > public IEnumerable<T> SomeMethod(Func<T> blah) > { /* ... */ } > } > > The MakeHostInstanceGeneric only sanitises the DeclaringType of the > MethodReference, but it does not sanitise method arguments, return-types, > and so on. And since the generic argument can be wrapped within another > generic type (e.g. IEnumerable<T> on the method above), the sanitation is > not exactly trivial. > > Using this unsanitised MethodReference (which still contains open > genericparameter types), it does not seem to produce a valid > OpCodes.CallVirt instruction. > > Any idea how to solve this? > > Cheers > > > On Mon, May 23, 2011 at 6:08 AM, Gábor Kozár <[email protected]> wrote: > >> This problem has been discussed several times already. >> Check out this discussion: >> >> >> http://groups.google.com/group/mono-cecil/browse_thread/thread/9826ade54b91e3b2?pli=1 >> >> In short: when you Resolve() a TypeReference or MethodReference (or any >> other reference), you loose all generic arguments. You have to then restore >> those generic arguments by essentially cloning the MethodReference (in your >> case), except setting its DeclaringType to the original TypeReference >> (which still contains the generic arguments). >> The discussion above contains several extension methods that will make >> this easier for you, but it's important that you know the concept. >> >> 2011/5/22 Jean-Paul Mayer <[email protected]> >> >>> >>> I am working on a problem where I want to replace a method on a class >>> with >>> a new method. >>> >>> I want to transform this: >>> >>> public class Foo { >>> public int Bar(){ >>> return 0; >>> } >>> }; >>> >>> into this: >>> >>> public class Foo { >>> public int _Call_Bar(string a, string b){ >>> return 0; >>> } >>> >>> public int Bar(string a, string b){ >>> try { >>> //do some preprocessing >>> return _Call_Bar(a, b); >>> } finally { >>> //post processing >>> } >>> } >>> } >>> >>> I have it mostly working. However, when Foo has a generic parameter (IE, >>> public class Foo<T>) then the generated IL looks to be incorrect. >>> >>> I end up with a call to >>> >>> L_000d: call instance int32 Demo.Foo`1::_Call_Bar(!T, !T) >>> >>> However, when I try to use this new type in an assembly it fails with a >>> type load exception (PEVerify says the assembly is verified). >>> >>> I tried to look at the compiler generated IL as if I had do the >>> transformation manually, and it ends up with a slightly different call >>> >>> >>> L_000d: call instance int32 Demo.Foo`1<!T>::_Call_Bar(!T, !T) >>> >>> >>> It looks like the call doesn't know anything about the generic type of >>> Foo? >>> >>> How can I say that the call to _Call_Bar is for type Foo<T>? >>> >>> Thanks, >>> >>> JP >>> >>> -- >>> -- >>> mono-cecil >> >> >> -- >> -- >> mono-cecil > > > -- -- mono-cecil
