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
