Mono.Cecil: call GENERIC base class' method from other assembly

前端 未结 1 974
时光取名叫无心
时光取名叫无心 2021-01-01 01:35

I\'m following up on my earlier question: Mono.Cecil: call base class' method from other assembly.
I\'m doing the same thing, but if my base class is generic it does

1条回答
  •  说谎
    说谎 (楼主)
    2021-01-01 02:01

    In your previous post you indicate that you're using code like:

    TypeDefinition type = ...;
    TypeDefintion baseType = type.BaseType.Resolve ();
    MethodDefinition baseMethod = baseType.Methods.First (m => ...);
    MethodReference baseMethodReference = type.Module.Import (baseMethod);
    il.Emit (OpCodes.Call, baseMethodReference);
    

    Obviously, this is not suitable for generics:

    When you Resolve () the .BaseType, you're losing the generic instantiation information. You need to recreate the appropriate method call with the proper generic information from the base type.

    To simplify things, let's use the following methods, taken from the Cecil test suite:

    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, params TypeReference [] arguments)
    {
        var reference = new MethodReference(self.Name,self.ReturnType) {
            DeclaringType = self.DeclaringType.MakeGenericType (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;
    }
    

    With those, you can rewrite your code as:

    TypeDefinition type = ...;
    TypeDefintion baseTypeDefinition = type.BaseType.Resolve ();
    MethodDefinition baseMethodDefinition = baseTypeDefinition.Methods.First (m => ...);
    MethodReference baseMethodReference = type.Module.Import (baseMethodDefinition);
    if (type.BaseType.IsGenericInstance) {
        var baseTypeInstance = (GenericInstanceType) type.BaseType;
        baseMethodReference = baseMethodReference.MakeGeneric (baseTypeInstance.GenericArguments.ToArray ());
    }
    
    il.Emit (OpCodes.Call, baseMethodReference);
    

    0 讨论(0)
提交回复
热议问题