Ejemplo n.º 1
0
    /// <summary>
    /// Weave an implementation of a method against the provided type.
    /// </summary>
    /// <param name="emitter">The emitter.</param>
    /// <param name="field">The attribute field.</param>
    /// <param name="method">The method.</param>
    /// <param name="interfaceType">The type of the interface.</param>
    public void WeaveImplementedMethod(TypeEmitter emitter, Variable field, MethodReference method, TypeDefinition interfaceType)
    {
        var resolved = method.Resolve();

        var emitted = emitter.EmitMethod(
            method.Name,
            method.ReturnType.Import(),
            parameterTypes: method.HasParameters ? method.Parameters.Select(p => p.ParameterType.Import()).ToArray() : new TypeReference[0],
            genericTypes: method.HasGenericParameters ? method.GenericParameters.ToArray() : new GenericParameter[0],
            toStatic: resolved.IsStatic,
            toVisibility: resolved.GetVisiblity()
            );

        var parameters  = method.Parameters.Select(p => p.ParameterType).ToArray();
        var generics    = method.GenericParameters.ToArray();
        var implemented = field.Type.GetMethod(method.Name, returns: method.ReturnType, parameters: parameters, generics: generics);

        if (implemented == null)
        {
            implemented = field.Type.GetMethod($"{interfaceType.FullName}.{method.Name}", returns: method.ReturnType, parameters: parameters, generics: generics);

            if (implemented == null)
            {
                throw new MissingMemberException($"Cannot implement '{field.Type.FullName}' as it does not implement method '{method.FullName}'");
            }
        }

        var il = emitted.GetIL();

        il.Emit(Codes.Nop);
        il.Emit(Codes.ThisIf(field));
        il.Emit(Codes.Load(field));

        for (int i = 0, count = method.Parameters.Count; i < count; i++)
        {
            il.Emit(Codes.Arg(i + 1));
        }

        il.Emit(Codes.Invoke(method.Import().GetGeneric()));
        il.Emit(Codes.Return);

        emitted.Body.InitLocals = true;
    }