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(genericArg);
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