Very nice article indeed, congratulations!

Ironically, it was the very same thing - method caching - that got me into
Cecil, although now I'm working on something more like PostSharp. Perhaps
I'll release its source code when I get somewhere with it (i.e. it actually
becomes useful).

Thanks for the mention in the credits! I'm honored!

2011/5/13 seesharper <[email protected]>

> Thanks a lot for your help!
>
> Here is what I needed this stuff for anyway.
>
> http://www.codeproject.com/KB/cs/MethodCaching.aspx
>
> Credit goes out to you at the end of the article.
>
> Best regards
>
> Bernhard Richter
>
> On May 8, 9:35 pm, Gábor Kozár <[email protected]> wrote:
> > You're welcome. :) Sure, go ahead and use it.
> >
> > I just wrote a couple of extension methods that should make it easy to
> use
> > generics:http://pastebin.com/BTX3AvpV
> > I have quickly ported my application to use them, and everything appears
> to
> > be working - but please do not take it for granted.
> >
> > They should reduce your code to:
> >
> > TypeReference genericArg = _moduleDefinition.TypeSystem.Int32;
> > GenericInstanceType genericType =
> >
> _moduleDefinition.Import(typeof(Nullable<>)).MakeGenericInstanceType(generi
> cArg);
> > MethodReference ctor =
> > _moduleDefinition.Import(genericType.ReferenceMethod(m => m.IsConstructor
> &&
> > m.Parameters.Count == 1));
> >
> > I hope that's better. :) Just keep in mind that Resolve() will drop all
> your
> > generic arguments, and all will be fine.
> >
> > Jb might want to consider adding them to Cecil.Rocks - I'm quite sure
> > numerous people would either welcome them, or have already written their
> > own. :)
> >
> > 2011/5/8 seesharper <[email protected]>
> >
> >
> >
> >
> >
> >
> >
> > > And it works!!!!!!!!!!!!!!!
> >
> > > Thanks a lot for your help! You are a true life saver :)
> >
> > > I did not find the extension method in Cecil.Rocks.
> >
> > > Is it okay if I use your method(MakeHostInstanceGeneric) in my code?
> >
> > > //bernhard
> >
> > > On May 8, 9:07 pm, Gábor Kozár <[email protected]> wrote:
> > > > Sorry, in my last e-mail I mentioned a 'call' instruction: you need
> the
> > > > 'newobj' instruction.
> >
> > > > Also, I'm stupid: we first need to import the MethodReference before
> > > you're
> > > > actually able to use it. So your code is:
> >
> > > > TypeReference genericArg = _moduleDefinition.TypeSystem.Int32;
> > > > GenericInstanceType genericType =
> >
> > >
> _moduleDefinition.Import(typeof(Nullable<>)).MakeGenericInstanceType(generi
> > > cArg);
> > > > MethodReference ctor =
> > > > _moduleDefinition.Import(genericType.Resolve().Methods.First(m =>
> > > > m.IsConstructor && m.Parameters.Count ==
> > > > 1).MakeHostInstanceGeneric(genericArg));
> >
> > > > Now it should be fine, it almost exactly matches the code in my
> > > application.
> > > > Sorry, it was my mistake. :(
> >
> > > > 2011/5/8 seesharper <[email protected]>
> >
> > > > > Hi again and we are getting closer and closer.
> >
> > > > > I just can't believe how difficult it is to work with generics.
> >
> > > > > It looks right now, but PEVerify throws an exception
> >
> > > > > [MD]: Error: Signature has an invalid token (token: 0x0200031d;
> > > > > offset: 0x00000002). [token:0x1B000001]
> > > > > [MD]: Error: Signature has generic type of arity 0 instantiated at
> > > > > different arity 1 at byte=0x00000005. [token:0x1B000001]
> > > > > [IL]: Error: [C:\Users\Bernhard\Documents\Visual Studio
> 2010\Projects
> > > > > \MethodCaching\TestResults\Tests[1]\Out\SampleLibrary.dll :
> > > > > SampleLibrary.SampleClass::Calculate][mdToken=0x6000001][offset
> > > > > 0x00000001] Unable to resolve token.
> > > > > 3 Error(s) Verifying SampleLibrary.dll
> >
> > > > > Could I ask you a BIG favor?
> >
> > > > > Could you try this out yourself and see if it works on your side?
> >
> > > > > I have been ripping my hair out for two days over this :)
> >
> > > > > //Bernhard
> >
> > > > > On May 8, 8:19 pm, Gábor Kozár <[email protected]> wrote:
> > > > > > Hey,
> >
> > > > > > Resolve() will make you lose all your generic arguments. If you
> can't
> > > > > change
> > > > > > the DeclaringType, then you have to clone the entire method. I
> have
> > > an
> > > > > > extension method for this, I believe it's also somewhere in
> > > Cecil.Rocks
> > > > > > (maybe under a different name).
> >
> > > > > > public static MethodReference MakeHostInstanceGeneric(this
> > > > > MethodReference
> > > > > > self, params TypeReference[] arguments)
> > > > > > {
> > > > > >       var reference = new MethodReference(self.Name,
> self.ReturnType,
> > > > > > self.DeclaringType.MakeGenericInstanceType(arguments))
> > > > > >       {
> > > > > >           HasThis = self.HasThis,
> > > > > >           ExplicitThis = self.ExplicitThis,
> > > > > >           CallingConvention = self.CallingConvention
> > > > > >       };
> >
> > > > > >       foreach (var parameter in self.Parameters)
> > > > > >           reference.Parameters.Add(new
> > > > > > ParameterDefinition(parameter.ParameterType));
> >
> > > > > >       foreach (var generic_parameter in self.GenericParameters)
> > > > > >           reference.GenericParameters.Add(new
> > > > > > GenericParameter(generic_parameter.Name, reference));
> >
> > > > > >       return reference;
> >
> > > > > > }
> >
> > > > > > So your code:
> >
> > > > > > TypeReference genericArg = _moduleDefinition.TypeSystem.Int32;
> > > > > > GenericInstanceType genericType =
> >
> > >
> _moduleDefinition.Import(typeof(Nullable<>)).MakeGenericInstanceType(generi
> > > > > cArg);
> > > > > > MethodReference ctor = genericType.Resolve().Methods.First(m =>
> > > > > > m.IsConstructor && m.Parameters.Count ==
> > > > > > 1).MakeHostInstanceGeneric(genericArg);
> >
> > > > > > And now you should be able to emit your call instruction.
> >
> > > > > > 2011/5/8 seesharper <[email protected]>
> >
> > > > > > > Hi Gábor and thanks for you help!!
> >
> > > > > > > Sadly it did not quite work out.
> >
> > > > > > > The ctor.DeclaringType is a TypeDefinition and I can't assign
> the
> > > > > > > result of
> >
> > > > > > > ctor.DeclaringType.MakeGenericInstanceType(genericArg)
> >
> > > > > > > If I do
> > > ctor.DeclaringType.MakeGenericInstanceType(genericArg).Resolve
> > > > > > > it will turn my generic type into a
> > > > > > > TypeDefiniton with all its generic type information lost. In
> other
> > > > > > > words back to where I started.
> >
> > > > > > > Any thoughts on this?
> >
> > > > > > > Regards
> >
> > > > > > > Bernhard Richter
> >
> > > > > > > On May 8, 12:11 pm, Gábor Kozár <[email protected]> wrote:
> > > > > > > > Hi,
> >
> > > > > > > > I've had the same issue before, but I've managed to solve it
> with
> > > the
> > > > > > > help
> > > > > > > > of Jb.
> >
> > > > > > > > What you need to do is the following:
> >
> > > > > > > > TypeReference genericArg =
> _moduleDefinition.TypeSystem.Int32;
> > > > > > > > GenericInstanceType genericType =
> > > > > > > > _moduleDefinition.Import(typeof(Nullable<>))
> > > > > > > > .MakeGenericInstanceType(genericArg);
> > > > > > > > MethodDefinition ctor = genericType.Resolve().Methods.First(m
> =>
> > > > > > > > m.IsConstructor && m.Parameters.Count == 1);
> >
> > > > > > > > Note that if you try to emit a newobj instruction with 'ctor'
> > > with
> > > > > its
> > > > > > > > operand at this point, you'll get invalid IL, because when
> you
> > > use
> > > > > > > > Resolve(), you lose all generic argument information. We need
> to
> > > > > provide
> > > > > > > > that manually.
> > > > > > > > For that, you have to add your generic argument to
> > > > > ctor.DeclaringType, or
> > > > > > > > alternatively, you can use Rocks' MakeGenericInstanceType,
> like
> > > so:
> >
> > > > > > > > ctor.DeclaringType =
> > > > > > > ctor.DeclaringType.MakeGenericInstanceType(genericArg);
> >
> > > > > > > > Now you can emit your newobj instruction with 'ctor' being
> its
> > > > > argument.
> > > > > > > > Note that you _might_ need to clone ctor.DeclaringType first
> (I'm
> > > not
> > > > > > > sure,
> > > > > > > > I don't have my code in front of me atm), but you get the
> general
> > > > > idea.
> >
> > > > > > > > Hope this helps!
> >
> > > > > > > > 2011/5/8 seesharper <[email protected]>
> >
> > > > > > > > > Hi!
> >
> > > > > > > > > I don't understand how to emit the code to create an
> instance
> > > of a
> > > > > > > > > generic type.
> >
> > > > > > > > > Mono.Cecil 0.9.4.0
> >
> > > > > > > > > I will illustrate this with a very simple example.
> >
> > > > > > > > > This is the code that I want to emit.
> >
> > > > > > > > >       public void TestNull(int value)
> > > > > > > > >        {
> > > > > > > > >            Nullable<int> test = value;
> > > > > > > > >        }
> >
> > > > > > > > > NOTE:
> >
> > > > > > > > > I don't know that the generic argument is an int at the
> time of
> > > > > > > > > emitting the code.
> >
> > > > > > > > > I need to read the parameter type and create a Nullable<T>
> > > > > according
> > > > > > > > > to the parameter type.
> >
> > > > > > > > > This means that I CAN'T do something like:
> >
> > > > > > > > > MethodReference ctor = _moduleDefinition.Import(typeof
> > > > > > > > > (Nullable<int>).GetConstructor(new Type[] {typeof (int)}));
> >
> > > > > > > > > This is the IL code that needs to be emitted.
> >
> > > > > > > > >    .maxstack 2
> > > > > > > > >    .locals init (
> > > > > > > > >        [0] valuetype [mscorlib]System.Nullable`1<int32>
> test)
> > > > > > > > >    L_0000: nop
> > > > > > > > >    L_0001: ldloca.s test
> > > > > > > > >    L_0003: ldarg.1
> > > > > > > > >    L_0004: call instance void
> > > > > > > > > [mscorlib]System.Nullable`1<int32>::.ctor(!0)
> > > > > > > > >    L_0009: nop
> > > > > > > > >    L_000a: ret
> >
> > > > > > > > > So this is what I got so far.
> >
> > > > > > > > > First a create a GenericInstanceType:
> >
> > > > > > > > > var nullableType =
> > > _moduleDefinition.Import(typeof(Nullable<>));
> > > > > > > > > var genericType =
> >
> > >
> nullableType.MakeGenericInstanceType(_moduleDefinition.Import(typeof(int)))
> > > > > > > ;
> >
> > > > > > > > > (yeah, I used the Cecil.Rocks extension method for creating
> the
> > > > > > > > > generic instance type, but that is not the issue here.)
> >
> > > > > > > > > The int would be the type from the value parameter of the
> > > TestNull
> > > > > > > > > method.
> >
> > > > > > > > > Now I have a GenericInstanceType that represents
> Nullable<int>.
> >
> > > > > > > > > But how do I create a MethodReference that represents the
> > > > > constructor
> > > > > > > > > passed to OpCodes.NewObj?
> >
> > > > > > > > > The GenericInstanceType which is derived from
> MethodReference
> > > does
> > > > > not
> > > > > > > > > have a collection of methods so I can't get it from there
> > > either.
> >
> > > > > > > > > Next I tried something like this:
> >
> > > > > > > > > MethodReference constructorReference = new
> > > MethodReference(".ctor",
> > > > > > > > > _moduleDefinition.Import(typeof(void)), genericType);
> >
> > > > > > > > > No luck on this either.
> >
> > > > > > > > > A lot of forum posts suggests that the methodreference
> should
> > > be
> > > > > added
> > > > > > > > > to the MemberReferences collection of the module.
> >
> > > > > > > > > But that is a read-only collection available from the
> > > > > > > > > GetMemberReferences method.
> >
> > > > > > > > > I must be missing something?
> >
> > ...
> >
> > read more »
>
> --
> --
> mono-cecil

-- 
--
mono-cecil

Reply via email to