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