Resolve() and generics

542 views
Skip to first unread message

Gábor Kozár

unread,
Jul 3, 2010, 2:39:29 PM7/3/10
to mono-...@googlegroups.com
When I have a MethodReference or TypeReference representing a generic method call / object instance, calling Resolve() seems to eliminate the generic arguments, resulting in invalid references in the CIL code. Is this intentional?
The problem is that I need to call Resolve(), then manipulate the resulting definition object, and I also have to preserve (and manipulate) the generic arguments (if any).

Any hints?

Thank you!

Jb Evain

unread,
Jul 3, 2010, 2:48:27 PM7/3/10
to mono-...@googlegroups.com
Hey,

On Sat, Jul 3, 2010 at 8:39 PM, Gábor Kozár <kozar...@gmail.com> wrote:
> When I have a MethodReference or TypeReference representing a generic method
> call / object instance, calling Resolve() seems to eliminate the generic
> arguments, resulting in invalid references in the CIL code. Is this
> intentional?

Yes. Resolve returns the corresponding *Definition. There's currently
nothing builtin that does a Resolve + rebuilding of a type spec.

> The problem is that I need to call Resolve(), then manipulate the resulting
> definition object, and I also have to preserve (and manipulate) the generic
> arguments (if any).
> Any hints?

Just implement it on top of Resolve, something like:

public static TypeReference ResolvePreserve (this TypeReference self)
{
if (self.IsGenericInstance) {
var previous_instance = (GenericInstanceType) self;
var instance = new GenericInstanceType
(previous_instance.ElementType.ResolvePreserve ());
foreach (var argument in previous_instance.GenericArguments)
instance.GenericArguments.Add (argument.ResolvePreserve ());
}

if (self.IsArray) {
// ..
}

if (self.IsByReference) {
//
}

return self.Resolve ();
}

--
Jb Evain <j...@nurv.fr>

Gábor Kozár

unread,
Jul 3, 2010, 3:33:33 PM7/3/10
to mono-...@googlegroups.com
I had a similar idea myself. Thank you!

2010/7/3 Jb Evain <j...@nurv.fr>
--
--
mono-cecil

Gábor Kozár

unread,
Jul 5, 2010, 7:24:45 AM7/5/10
to mono-...@googlegroups.com
Well, this doesn't seem to be working. I attached my code (it's a little bit long and the indentation is lost if I copy it in here) - I'm getting an InvalidCastException: Unable to cast object of type 'Mono.Cecil.GenericInstanceMethod' to type 'Mono.Cecil.IMemberDefinition'.

I need an IMemberDefinition, but there seem to be no way of having one. What am I doing wrong?

Thank you!

2010/7/3 Jb Evain <j...@nurv.fr>
Hey,
--
--
mono-cecil

ResolvePreserve.txt

Jb Evain

unread,
Jul 5, 2010, 8:27:30 AM7/5/10
to mono-...@googlegroups.com
On Mon, Jul 5, 2010 at 1:24 PM, Gábor Kozár <kozar...@gmail.com> wrote:
> I need an IMemberDefinition, but there seem to be no way of having one. What
> am I doing wrong?

IGenericInstance and IMemberDefinition are completely different
interfaces, you can't cast a IGenericInstance to a IMemberDefinition.
The lowest common denominator here is MemberReference.

You're trying to do to much in one method.

You should have different cases:

TypeReference ResolvePreserved (this TypeReference type)
MethodReference ResolvePreserved (this MethodReference method)
FieldReference ResolvePreserved (this FieldReference field)

The first one needs to deal with type specs like in the code I pasted
here, and the second needs to deal with method specs.

--
Jb Evain <j...@nurv.fr>

Gábor Kozár

unread,
Jul 5, 2010, 9:10:12 AM7/5/10
to mono-...@googlegroups.com
It doesn't matter if I have 3 methods or 1; the point is that I need this:

TypeDefinition ResolvePreserve(TypeReference)

And a GenericInstanceMethod cannot be cast to TypeDefinition, only TypeReference, but I don't need a TypeReference. I need a TypeDefinition.

What I have seen so far lets me think that it is impossible (by design) for a TypeDefinition (or any Definition) to have generic arguments. Or can it be solved?

2010/7/5 Jb Evain <j...@nurv.fr>
Jb Evain  <j...@nurv.fr>

--
--
mono-cecil

Jb Evain

unread,
Jul 5, 2010, 9:34:32 AM7/5/10
to mono-...@googlegroups.com
On Mon, Jul 5, 2010 at 3:10 PM, Gábor Kozár <kozar...@gmail.com> wrote:
> It doesn't matter if I have 3 methods or 1; the point is that I need this:
>
> TypeDefinition ResolvePreserve(TypeReference)

Indeed proper design doesn't matter if you want something that can't
possibly exist.

> And a GenericInstanceMethod cannot be cast to TypeDefinition, only
> TypeReference, but I don't need a TypeReference. I need a TypeDefinition.
> What I have seen so far lets me think that it is impossible (by design) for
> a TypeDefinition (or any Definition) to have generic arguments. Or can it be
> solved?

ResolvePreserve can only return a TypeReference because it's the root
of all types. Let's try to make it simple for you.
In your assembly, you have a TypeReference to List<string>.

What you actually have is:

GenericInstanceType
ElementType: TypeReference(List`1)
GenericArguments: TypeReference(String)

Now with ResolvePreserved you want:

GenericInstanceType
ElementType: TypeDefinition(List`1)
GenericArguments: TypeDefinition(String)

And the hierarchy of GenericInstanceType is: TypeReference ->
TypeSpecification -> GenericInstanceType.

So ResolvePreserve needs to return a TypeReference for all
TypeSpecifications, such as arrays. And it's ok, you can write:

TypeReference ResolvePreserved (this TypeReference self);

TypeReference resolved = type.ResolvePreserved ();
if (resolved.IsDefinition) {
TypeDefinition definition = (TypeDefinition) resolved;
// ...
}

--
Jb Evain <j...@nurv.fr>

Gábor Kozár

unread,
Jul 5, 2010, 9:51:09 AM7/5/10
to mono-...@googlegroups.com
Okay, I see the problem. Nonetheless, I have to make this work somehow.
I'm currently trying something like:

public static MethodReference ResolveTransform(this MethodReference methodRef, Func<TypeReference, TypeReference> genericArgTransformer, Func<MethodDefinition, MethodDefinition> resolvedMethodTransformer) { ... }

And something similar for TypeReference. The idea is that I cannot have a TypeDefinition while I have generic arguments, so lets split the task: genericArgTransformer is called for each and every generic arguments there is in the TypeReference (or MethodReference), which executes its task (i.e. moving the types to the exe file), and somewhere, deep within there also must be a MethodDefinition (below all generic arguments), which is also processed seperately.

In theory this should work (at least I couldn't yet find out why shouldn't it), though I have to rewrite the code in many parts.

Thanks for your help anyway!

2010/7/5 Jb Evain <j...@nurv.fr>
Jb Evain  <j...@nurv.fr>

--
--
mono-cecil

Reply all
Reply to author
Forward
0 new messages