/// <summary> /// Create a new method in the declaring type of the given implicit implementation with the given name. /// This method will call the implicit implementation. /// </summary> internal static MethodDefinition CreateExplicitStub(MethodDefinition implicitImpl, string name, MethodDefinition iMethod, bool avoidGenericParam) { // Create method var newMethod = new MethodDefinition(name, implicitImpl.Attributes, implicitImpl.ReturnType); newMethod.IsVirtual = false; newMethod.IsAbstract = false; newMethod.IsFinal = true; // Clone generic parameters foreach (var gp in implicitImpl.GenericParameters) { newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod)); } // Update according to new context var cloner = new TypeCloner(avoidGenericParam, implicitImpl.Module.TypeSystem); newMethod.ReturnType = cloner.Get(implicitImpl.ReturnType, newMethod); // Clone parameters foreach (var p in iMethod.Parameters) { newMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, newMethod))); } // Add the method var targetType = implicitImpl.DeclaringType; targetType.Methods.Add(newMethod); // Add override newMethod.Overrides.Add(iMethod); // Create method body var body = new MethodBody(newMethod); newMethod.Body = body; var worker = body.GetILProcessor(); // Push this worker.Emit(OpCodes.Ldarg, body.ThisParameter); for (var i = 0; i < implicitImpl.Parameters.Count; i++) { var p = iMethod.Parameters[i]; var newMethodParam = newMethod.Parameters[i]; worker.Emit(OpCodes.Ldarg, newMethodParam); if (/*avoidGenericParam &&*/ p.ParameterType.ContainsGenericParameter) { worker.Emit(OpCodes.Box, implicitImpl.Parameters[i].ParameterType); } } worker.Emit(implicitImpl.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, implicitImpl); worker.Emit(OpCodes.Ret); // Mark method reachable if (implicitImpl.IsReachable) { newMethod.SetReachable(null); } return newMethod; }
/// <summary> /// Add a method that has the same signature as basemethod and calls method. /// </summary> private MethodDefinition AddBridge(MethodDefinition method, MethodDefinition baseMethod) { var bridge = new MethodDefinition(baseMethod.Name, baseMethod.Attributes, baseMethod.ReturnType) { HasThis = true }; var cloner = new TypeCloner(true, method.Module.TypeSystem); bridge.ReturnType = cloner.Get(baseMethod.ReturnType, bridge); bridge.IsAbstract = false; // Clone parameters foreach (var p in baseMethod.Parameters) { bridge.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, bridge))); } // Create body var body = new MethodBody(bridge); bridge.Body = body; // Create code var seq = new ILSequence(); // this seq.Emit(OpCodes.Ldarg_0); // parameters for (var i = 0; i < bridge.Parameters.Count; i++) { var p = bridge.Parameters[i]; seq.Emit(OpCodes.Ldarg, p); if (baseMethod.Parameters[i].ParameterType.ContainsGenericParameter) { seq.Emit(OpCodes.Unbox, method.Parameters[i].ParameterType); } } // Call actual method seq.Emit(OpCodes.Call, method); // Return seq.Emit(OpCodes.Ret); // Add code to body seq.AppendTo(body); body.ComputeOffsets(); // add overrides, so that we can find the method later bridge.Overrides.Add(baseMethod); // Add to class method.DeclaringType.Methods.Add(bridge); bridge.SetReachable(reachableContext); return(bridge); }
/// <summary> /// Add a method that has the same signature as basemethod and calls method. /// </summary> private MethodDefinition AddBridge(MethodDefinition method, MethodDefinition baseMethod) { var bridge = new MethodDefinition(baseMethod.Name, baseMethod.Attributes, baseMethod.ReturnType) { HasThis = true }; var cloner = new TypeCloner(true, method.Module.TypeSystem); bridge.ReturnType = cloner.Get(baseMethod.ReturnType, bridge); bridge.IsAbstract = false; // Clone parameters foreach (var p in baseMethod.Parameters) { bridge.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, bridge))); } // Create body var body = new MethodBody(bridge); bridge.Body = body; // Create code var seq = new ILSequence(); // this seq.Emit(OpCodes.Ldarg_0); // parameters for (var i = 0; i < bridge.Parameters.Count; i++) { var p = bridge.Parameters[i]; seq.Emit(OpCodes.Ldarg, p); if (baseMethod.Parameters[i].ParameterType.ContainsGenericParameter) { seq.Emit(OpCodes.Unbox, method.Parameters[i].ParameterType); } } // Call actual method seq.Emit(OpCodes.Call, method); // Return seq.Emit(OpCodes.Ret); // Add code to body seq.AppendTo(body); body.ComputeOffsets(); // add overrides, so that we can find the method later bridge.Overrides.Add(baseMethod); // Add to class method.DeclaringType.Methods.Add(bridge); bridge.SetReachable(reachableContext); return bridge; }
/// <summary> /// Create a new method in the declaring type of the given implicit implementation with the given name. /// This method will call the implicit implementation. /// </summary> internal static MethodDefinition CreateExplicitStub(MethodDefinition implicitImpl, string name, MethodDefinition iMethod, bool avoidGenericParam) { // Create method var newMethod = new MethodDefinition(name, implicitImpl.Attributes, implicitImpl.ReturnType); newMethod.IsVirtual = false; newMethod.IsAbstract = false; newMethod.IsFinal = true; // Clone generic parameters foreach (var gp in implicitImpl.GenericParameters) { newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod)); } // Update according to new context var cloner = new TypeCloner(avoidGenericParam, implicitImpl.Module.TypeSystem); newMethod.ReturnType = cloner.Get(implicitImpl.ReturnType, newMethod); // Clone parameters foreach (var p in iMethod.Parameters) { newMethod.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, cloner.Get(p.ParameterType, newMethod))); } // Add the method var targetType = implicitImpl.DeclaringType; targetType.Methods.Add(newMethod); // Add override newMethod.Overrides.Add(iMethod); // Create method body var body = new MethodBody(newMethod); newMethod.Body = body; var worker = body.GetILProcessor(); // Push this worker.Emit(OpCodes.Ldarg, body.ThisParameter); for (var i = 0; i < implicitImpl.Parameters.Count; i++) { var p = iMethod.Parameters[i]; var newMethodParam = newMethod.Parameters[i]; worker.Emit(OpCodes.Ldarg, newMethodParam); if (/*avoidGenericParam &&*/ p.ParameterType.ContainsGenericParameter) { worker.Emit(OpCodes.Box, implicitImpl.Parameters[i].ParameterType); } } worker.Emit(implicitImpl.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, implicitImpl); worker.Emit(OpCodes.Ret); // Mark method reachable if (implicitImpl.IsReachable) { newMethod.SetReachable(null); } return(newMethod); }