private void CollectInterface(MethodSlotList slots, IType interfaceType) { var type = slots.Type; // Methods foreach (var interfaceBuildMethod in interfaceType.Methods) { var targetSlotMethod = slots.GetMethod(interfaceBuildMethod, true); if (targetSlotMethod.Depth == 0) { // Root type overrides interface. var targetBuildMethod = targetSlotMethod.Method; var targetMethodState = _state.GetMethod(targetBuildMethod); var interfaceMethodState = _state.GetMethod(interfaceBuildMethod); if (NeedsInterfaceOverride(interfaceMethodState, targetMethodState)) { targetMethodState.Overrides.Add(interfaceBuildMethod); } } else { // Base type overrides interface. var typeState = _state.GetType(type); var targetBuildMethod = targetSlotMethod.Method; // If not overriden by root type, build proxy method and call base method. if (typeState.Overrides.Contains(interfaceBuildMethod)) { continue; } // If base method could not be called from this type, skip proxy method. // If assembly is valid base method is always callable. if (!CanCallMethod(type, targetBuildMethod)) { continue; } // Add proxy method. var proxy = new ProxyBuildMethod() { OverridenMethod = interfaceBuildMethod, CalledMethod = targetBuildMethod, }; typeState.ProxyMethods.Add(proxy); typeState.Overrides.Add(interfaceBuildMethod); } } // Children foreach (var childInterfaceType in interfaceType.Interfaces) { CollectInterface(slots, childInterfaceType); } }
private void ChangeProxyMethod(BuildType type, ProxyBuildMethod proxyMethod) { var overridenMethod = proxyMethod.OverridenMethod; var calledMethod = proxyMethod.CalledMethod; var method = type.Methods.Add(); method.Name = _nameGenerator.GenerateUniqueString(); method.Visibility = MethodVisibilityFlags.Private; method.HasThis = true; method.IsHideBySig = true; method.IsVirtual = true; method.IsNewSlot = true; method.IsFinal = true; method.CallConv = overridenMethod.CallConv; // Return type { var returnType = method.ReturnType; returnType.Type = overridenMethod.ReturnType.ToSignature(type.Module); } // Parameters foreach (var overridenMethodParameter in overridenMethod.Parameters) { var parameter = method.Parameters.Add(); parameter.Name = overridenMethodParameter.Name; parameter.IsIn = overridenMethodParameter.IsIn; parameter.IsOut = overridenMethodParameter.IsOut; parameter.IsOptional = overridenMethodParameter.IsOptional; parameter.IsLcid = overridenMethodParameter.IsLcid; parameter.Type = overridenMethodParameter.Type.ToSignature(type.Module); } // GenericParameters foreach (var interfaceGenericParameter in overridenMethod.GenericParameters) { var genericParameter = method.GenericParameters.Add(); genericParameter.Name = interfaceGenericParameter.Name; genericParameter.Variance = interfaceGenericParameter.Variance; genericParameter.DefaultConstructorConstraint = interfaceGenericParameter.DefaultConstructorConstraint; genericParameter.ReferenceTypeConstraint = interfaceGenericParameter.ReferenceTypeConstraint; genericParameter.ValueTypeConstraint = interfaceGenericParameter.ValueTypeConstraint; // Constraints foreach (var constraintType in interfaceGenericParameter.Constraints) { genericParameter.Constraints.Add(constraintType.ToSignature(type.Module)); } } // Body { var methodBody = new MethodBody(); // Instructions var instructions = methodBody.Instructions; methodBody.MaxStackSize = method.Parameters.Count + 2; // this + parameters + return // Load this instructions.Add(Instruction.GetLdarg(0)); // Load parameters for (int i = 0; i < method.Parameters.Count; i++) { instructions.Add(Instruction.GetLdarg(i + 1)); } var calledMethodSig = calledMethod.ToSignature(type.Module); if (calledMethod.GenericParameters.Count > 0) { var genericArguments = new TypeSignature[calledMethod.GenericParameters.Count]; for (int i = 0; i < genericArguments.Length; i++) { genericArguments[i] = new GenericParameterType(true, i); } calledMethodSig = new GenericMethodReference((MethodReference)calledMethodSig, genericArguments); } // Call method instructions.Add(new Instruction( calledMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, calledMethodSig)); instructions.Add(new Instruction(OpCodes.Ret)); methodBody.Build(method); } // Add override. method.Overrides.Add(overridenMethod.ToReference(type.Module)); }