On Tue, May 18, 2010 at 5:32 PM, Timwi <[email protected]> wrote:
> However, to make sure that I don't keep running into this, I would
> like to understand this better. Could you explain to me exactly what I
> was doing wrong? You say I was using a MethodDefinition from corlib,
> but I don't see how — I was only using
> IEnumerableGetEnumerator.ReturnType, which I agree is from corlib, but
> shouldn't module.Import() then import it?

So you had this piece of code:

       var IEnumerable = IEnumerableU.GetElementType().Resolve();

       // This gets me the right method in the original,
       // non-constructed generic IEnumerable<T> type
       var IEnumerableGetEnumerator = IEnumerable.Methods.Single(
           m => m.Name == "GetEnumerator");

       // Try to add the override!
       TestUGetEnumerator.Overrides.Add(IEnumerableGetEnumerator);

The first line erases the generic instance to give you its element
type, and resolve returns its definition from the corlib.
You then get its GetEnumerator MethodDefinition, and you passed that
directly as an override.

So in that case, you were passing a foreign MethodDefinition.

> Also — I can kind of understand why your solution works, but how do
> you come up with it? It is unintuitive to me that I should have to
> fiddle with the DeclaringType property of the reference I got
> from .Import() instead of constructing a new reference cleanly — it
> feels kind of subversive. Does this have something to do with the way
> metadata tokens specify the relationship between types and methods,
> and if so, what exactly?

No, it was just a hack to get faster to get it working. In Cecil's
test suite, I have the following code:


                public static TypeReference MakeGenericType (this TypeReference
self, params TypeReference [] arguments)
                {
                        if (self.GenericParameters.Count != arguments.Length)
                                throw new ArgumentException ();

                        var instance = new GenericInstanceType (self);
                        foreach (var argument in arguments)
                                instance.GenericArguments.Add (argument);

                        return instance;
                }

                public static MethodReference MakeGeneric (this MethodReference
self, TypeReference declaringType)
                {
                        var reference = new MethodReference {
                                Name = self.Name,
                                DeclaringType = declaringType,
                                HasThis = self.HasThis,
                                ExplicitThis = self.ExplicitThis,
                                ReturnType = self.ReturnType,
                                CallingConvention = 
MethodCallingConvention.Generic,
                        };

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

                        return reference;
                }

So I could have write:

var IEnumerator_int = IEnumerable.MakeGenericType (TestU.GenericParameters [0]);
var GetEnumerator_ref = IEnumerableGetEnumerator.MakeGeneric (IEnumerator_int);

It would indeed be easier to read.

I think they should eventually move to Mono.Cecil.Rocks, but I'm not
fond of their name. But basically changing the declaring type of the
method reference is about going from the open MethodReference:

IEnumerator<!0> IEnumerable::GetEnumerator ()

to the closed:

IEnumerator<!0> IEnumerable<U>::GetEnumerator ()

Where U is the generic parameter of your X type.

-- 
Jb Evain  <[email protected]>

-- 
--
mono-cecil

Reply via email to