/// <summary> /// Creates a new property in the target assembly, but doesn't set its accessors. /// </summary> /// <param name="targetType">Type of the target.</param> /// <param name="yourProperty">Your property.</param> /// <param name="newPropAttr">The new property attribute.</param> /// <exception cref="PatchDeclerationException">Thrown if this member collides with another member, and the error cannot be resolved.</exception> private NewMemberStatus CreateNewProperty(TypeDefinition targetType, PropertyDefinition yourProperty, NewMemberAttribute newPropAttr) { if (newPropAttr.IsImplicit) { Log_implicitly_creating_member("property", yourProperty); } else { Log_creating_member("property", yourProperty); } var maybeDuplicate = targetType.GetProperty(yourProperty.Name, yourProperty.Parameters.Select(x => x.ParameterType)); if (maybeDuplicate != null) { Log_duplicate_member("property", yourProperty, maybeDuplicate); if ((DebugOptions & DebugFlags.CreationOverwrites) != 0) { Log_overwriting(); return(NewMemberStatus.Continue); } if (newPropAttr.IsImplicit) { return(NewMemberStatus.InvalidItem); } throw Errors.Duplicate_member("property", yourProperty.FullName, maybeDuplicate.FullName); } var targetPropertyType = FixTypeReference(yourProperty.PropertyType); var targetProperty = new PropertyDefinition(yourProperty.Name, yourProperty.Attributes, targetPropertyType) { HasThis = yourProperty.HasThis, Constant = yourProperty.Constant, HasDefault = yourProperty.HasDefault }; targetType.Properties.Add(targetProperty); foreach (var param in yourProperty.Parameters) { targetProperty.Parameters.Add(new ParameterDefinition(param.Name, param.Attributes, FixTypeReference(param.ParameterType))); } return(NewMemberStatus.Continue); }
/// <summary> /// Creates a new field in the target assembly, for the specified type. /// </summary> /// <param name="targetDeclaringType">The target declaring type.</param> /// <param name="yourField">Your field.</param> /// <param name="attr">The action attribute.</param> /// <exception cref="PatchDeclerationException">Thrown if this member collides with another member, and the error cannot be resolved.</exception> /// <returns></returns> private NewMemberStatus CreateNewField(TypeDefinition targetDeclaringType, FieldDefinition yourField, NewMemberAttribute attr) { if (attr.IsImplicit) { Log_implicitly_creating_member("field", yourField); } else { Log_creating_member("field", yourField); } var maybeDuplicate = targetDeclaringType.GetField(yourField.Name); if (maybeDuplicate != null) { Log_duplicate_member("field", yourField, maybeDuplicate); if ((DebugOptions & DebugFlags.CreationOverwrites) != 0) { Log_overwriting(); return(NewMemberStatus.Continue); } if (attr.IsImplicit) { return(NewMemberStatus.InvalidItem); } throw Errors.Duplicate_member("type", yourField.FullName, maybeDuplicate.FullName); } var targetField = new FieldDefinition(yourField.Name, yourField.Resolve().Attributes, FixTypeReference(yourField.FieldType)) { InitialValue = yourField.InitialValue, //probably for string consts Constant = yourField.Constant }; targetDeclaringType.Fields.Add(targetField); return(NewMemberStatus.Continue); }
/// <summary> /// Creates a new method in the target assembly, for the specified type. /// </summary> /// <param name="targetDeclaringType">The type declaring the method in the target assembly.</param> /// <param name="yourMethod">Your method, which describes the method to create..</param> /// <param name="actionAttribute">The action attribute ordering creation.</param> /// <returns></returns> /// <exception cref="PatchDeclerationException">Thrown if this member collides with another member, and the error cannot be resolved.</exception> private NewMemberStatus CreateNewMethod(TypeDefinition targetDeclaringType, MethodDefinition yourMethod, NewMemberAttribute actionAttribute) { if (actionAttribute.IsImplicit) { Log_implicitly_creating_member("method", yourMethod); } else { Log_creating_member("method", yourMethod); } var maybeDuplicate = targetDeclaringType.GetMethodsLike(yourMethod).FirstOrDefault(); if (maybeDuplicate != null) { Log_duplicate_member("method", yourMethod, maybeDuplicate); if ((DebugOptions & DebugFlags.CreationOverwrites) != 0) { Log_overwriting(); //this only okay for controlled testing code. return(NewMemberStatus.Continue); } if (actionAttribute.IsImplicit) { return(NewMemberStatus.InvalidItem); } throw Errors.Duplicate_member("type", yourMethod.FullName, maybeDuplicate.FullName); } var targetMethod = new MethodDefinition(yourMethod.Name, yourMethod.Attributes, yourMethod.ReturnType) { ImplAttributes = yourMethod.ImplAttributes, SemanticsAttributes = yourMethod.SemanticsAttributes, CallingConvention = yourMethod.CallingConvention, //all the Attributes and Conventions take care of most of the IsX/HasY properties, except for a few. //this can be seen by looking at the Cecil code, where you can see which fields MethodDefinition has. HasThis = yourMethod.HasThis, ExplicitThis = yourMethod.ExplicitThis, NoInlining = yourMethod.NoInlining, NoOptimization = yourMethod.NoOptimization, ReturnType = yourMethod.ReturnType //<---- this is temporary (setting it again to emphasize) }; targetMethod.SecurityDeclarations.AddRange(yourMethod.SecurityDeclarations.Select(x => new SecurityDeclaration(x.Action, x.GetBlob()))); targetDeclaringType.Methods.Add(targetMethod); //First we add the parameters to the method so its signature is correct. //Note that we do not fix the types at this stage. //This is because FixType calls can end up looking for the method we're adding right now //if any of the parameter types are MVars. The signature has to be similar to yourMethod's signature //if FixType is to find this definition. //this may seem needlessly complicated and rather risky, and I thought so too, but there really isn't any way around it //or at least, I'm not clever enough to come up with one that doesn't introduce more problems //(believe me, I've tried all sorts of things) foreach (var yourParam in yourMethod.Parameters) { targetMethod.Parameters.Add(new ParameterDefinition(yourParam.ParameterType)); } //Note we're not adding any constraints yet because doing that involves FixType calls //also, the T : S constraint involves 2 MVars, so unless we add all the MVars first, FixType calls could never be resolved. var genList = new List <GenericParameter>(); foreach (var yourTypeParam in yourMethod.GenericParameters) { var targetTypeParam = new GenericParameter(yourTypeParam.Name, targetMethod) { Attributes = yourTypeParam.Attributes //includes non-type constraints }; genList.Add(targetTypeParam); } targetMethod.GenericParameters.AddRange(genList); //NOW we're adding constraints, when the signature is stable and when all MVars have been declared. for (int i = 0; i < targetMethod.GenericParameters.Count; i++) { foreach (var constraint in yourMethod.GenericParameters[i].Constraints) { targetMethod.GenericParameters[i].Constraints.Add(FixTypeReference(constraint)); } } // note that we don't add the parameters to the method directly, at least not at first. //this is because we're making FixType calls, and again, they can end up looking up targetMethod //changing the signature will just end up with FixType not finding it. var parList = new List <ParameterDefinition>(); foreach (var yourParam in yourMethod.Parameters) { var targetParamType = FixTypeReference(yourParam.ParameterType); var targetParam = new ParameterDefinition(yourParam.Name, yourParam.Attributes, targetParamType) { Constant = yourParam.Constant, }; parList.Add(targetParam); } //we reset the parameters after we're done with that in as near an atomic operation as possible, and without any FixType calls. targetMethod.Parameters.Clear(); targetMethod.Parameters.AddRange(parList); //we also fix this guy: targetMethod.ReturnType = FixTypeReference(yourMethod.ReturnType); //note that YOU DO NOT do targetMethod.Parameters.AddRangE(yourMethod.Parameters) //ParameterDefinitions are mutable! and doing this can mutate them... return(NewMemberStatus.Continue); }