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?
>
> > > > Any help on this issue would be great!!!
>
> > > > Regards
>
> > > > Bernhard Richter
>
> > > > --
> > > > --
> > > > mono-cecil
>
> > --
> > --
> > mono-cecil

-- 
--
mono-cecil

Reply via email to