/// <summary> /// Does the given type have any instance field that is a struct? /// </summary> private static bool HasInstanceStructFields(TypeDefinition type, out List <FieldDefinition> structFields) { structFields = null; if (type.IsEnum) // Class ctor is already created automatically for enums { return(false); } if (type.Name.StartsWith("<PrivateImplementationDetails>")) { return(false); } foreach (var field in type.Fields.Where(x => !x.IsStatic && x.IsReachable && StructFields.IsStructField(x))) { if (structFields == null) { structFields = new List <FieldDefinition>(); } structFields.Add(field); } return(structFields != null); }
/// <summary> /// Create a CopyFrom method. /// </summary> private static MethodDefinition CreateCopyFromMethod(ReachableContext reachableContext, TypeDefinition type) { var typeSystem = type.Module.TypeSystem; var method = new MethodDefinition(NameConstants.Struct.CopyFromMethodName, MethodAttributes.Public, type); var sourceParam = new ParameterDefinition(type); method.Parameters.Add(sourceParam); method.DeclaringType = type; var body = new MethodBody(method); body.InitLocals = true; method.Body = body; // Prepare code var seq = new ILSequence(); seq.Emit(OpCodes.Nop); // Call base CopyFrom var baseType = (type.BaseType != null) ? type.BaseType.GetElementType().Resolve() : null; if ((baseType != null) && baseType.IsValueType && (baseType.FullName != "System.ValueType")) { var baseMethod = new MethodReference(NameConstants.Struct.CopyFromMethodName, baseType, baseType) { HasThis = true }; baseMethod.Parameters.Add(new ParameterDefinition(baseType)); seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Call, baseMethod); } // Copy all fields foreach (var field in type.Fields.Where(x => !x.IsStatic)) { TypeDefinition fieldTypeDef; var isStructField = StructFields.IsStructField(field, out fieldTypeDef); // Prepare for stfld seq.Emit(OpCodes.Ldarg, body.ThisParameter); // Load from source seq.Emit(OpCodes.Ldarg, sourceParam); seq.Emit(OpCodes.Ldfld, field); // If struct, create clone if (isStructField) { var cloneMethod = new MethodReference(NameConstants.Struct.CloneMethodName, fieldTypeDef, fieldTypeDef) { HasThis = true }; seq.Emit(OpCodes.Call, cloneMethod); } // Save in this seq.Emit(OpCodes.Stfld, field); } // Return this seq.Emit(OpCodes.Ldarg, body.ThisParameter); seq.Emit(OpCodes.Ret); // Append ret sequence seq.AppendTo(body); // Update offsets body.ComputeOffsets(); // Add method type.Methods.Add(method); method.SetReachable(reachableContext); return(method); }