private IEnumerable <Instruction> CopySet(TypeReference type, ValueSource source, ValueTarget target) { var typeOfArgument = type.GetGenericArguments().Single(); var list = new List <Instruction>(); using (new IfNotNull(list, source, target.IsTargetingBase)) { VariableDefinition variable = null; if (!target.IsTargetingBase) { list.AddRange(NewInstance(type, typeof(ISet <>), typeof(HashSet <>), out variable)); } using (var forEach = new ForEach(this, list, type, source)) { list.AddRange(Copy(typeOfArgument, ValueSource.New().Variable(forEach.Current), ValueTarget.New().Instance(variable).Callvirt(ImportMethod(type.Resolve(), nameof(ISet <object> .Add), typeOfArgument)).Add(OpCodes.Pop))); } if (!target.IsTargetingBase) { list.AddRange(target.Build(variable)); } } return(list); }
private void AddDeepConstructor(TypeDefinition type) { var constructor = new MethodDefinition(ConstructorName, ConstructorAttributes, TypeSystem.VoidReference); constructor.Parameters.Add(new ParameterDefinition(type)); var processor = constructor.Body.GetILProcessor(); Func <TypeReference, IEnumerable <Instruction> > baseCopyFunc = null; if (type.BaseType.Resolve().MetadataToken == TypeSystem.ObjectDefinition.MetadataToken) { processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, ImportDefaultConstructor(TypeSystem.ObjectDefinition)); } else if (IsCopyConstructorAvailable(type.BaseType, out var baseConstructor)) { processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Ldarg_1); processor.Emit(OpCodes.Call, baseConstructor); } else if (IsType(type.BaseType.GetElementType().Resolve(), typeof(Dictionary <,>))) { processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, ImportDefaultConstructor(type.BaseType)); baseCopyFunc = reference => CopyDictionary(reference, ValueSource.New(), ValueTarget.New()); } else if (IsType(type.BaseType.GetElementType().Resolve(), typeof(List <>))) { processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, ImportDefaultConstructor(type.BaseType)); baseCopyFunc = reference => CopyList(reference, ValueSource.New(), ValueTarget.New()); } else if (IsType(type.BaseType.GetElementType().Resolve(), typeof(HashSet <>))) { processor.Emit(OpCodes.Ldarg_0); processor.Emit(OpCodes.Call, ImportDefaultConstructor(type.BaseType)); baseCopyFunc = reference => CopySet(reference, ValueSource.New(), ValueTarget.New()); } else { throw new NoCopyConstructorFoundException(type.BaseType); } InsertCopyInstructions(type, constructor.Body, baseCopyFunc); processor.Emit(OpCodes.Ret); type.Methods.Add(constructor); }
private bool TryCopy(PropertyDefinition property, out IEnumerable <Instruction> instructions) { if (property.AnyAttribute(IgnoreDuringDeepCopyAttribute)) { property.CustomAttributes.Remove(property.SingleAttribute(IgnoreDuringDeepCopyAttribute)); instructions = null; return(false); } if (property.GetMethod == null || property.SetMethod == null && property.GetBackingField() == null) { instructions = null; return(false); } if (property.AnyAttribute(DeepCopyByReferenceAttribute)) { property.CustomAttributes.Remove(property.SingleAttribute(DeepCopyByReferenceAttribute)); instructions = new[] { Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Ldarg_1), Instruction.Create(OpCodes.Callvirt, property.GetMethod), property.CreateSetInstruction() }; return(true); } var source = ValueSource.New().Property(property); var target = ValueTarget.New().Property(property); var list = new List <Instruction>(); instructions = list; if (property.PropertyType.IsArray) { using (new IfNotNull(list, source)) list.AddRange(CopyArray(property)); return(true); } instructions = Copy(property.PropertyType, source, target); return(true); }
private IEnumerable <Instruction> CopyArrayItem(PropertyDefinition property, TypeReference elementType, VariableDefinition index) { if (!elementType.IsPrimitive && !elementType.IsValueType) { return(Copy(elementType, ValueSource.New().Property(property).Index(index), ValueTarget.New().Property(property).Index(index))); } var instructions = new List <Instruction> { Instruction.Create(OpCodes.Ldarg_0), Instruction.Create(OpCodes.Call, property.GetMethod), Instruction.Create(OpCodes.Ldloc, index), Instruction.Create(OpCodes.Ldarg_1), Instruction.Create(OpCodes.Callvirt, property.GetMethod), Instruction.Create(OpCodes.Ldloc, index), Instruction.Create(OpCodes.Ldelem_I4), Instruction.Create(OpCodes.Stelem_I4) }; return(instructions); }
private IEnumerable <Instruction> CopyDictionary(TypeReference type, ValueSource source, ValueTarget target) { var typesOfArguments = type.GetGenericArguments(); var typeKeyValuePair = ImportType(typeof(KeyValuePair <,>), typesOfArguments); var list = new List <Instruction>(); using (new IfNotNull(list, source, target.IsTargetingBase)) { VariableDefinition variable = null; if (!target.IsTargetingBase) { list.AddRange(NewInstance(type, typeof(IDictionary <,>), typeof(Dictionary <,>), out variable)); } using (var forEach = new ForEach(this, list, type, source)) { var sourceKey = ValueSource.New().Variable(forEach.Current).Method(ImportMethod(typeKeyValuePair, "get_Key", typesOfArguments)); var sourceValue = ValueSource.New().Variable(forEach.Current).Method(ImportMethod(typeKeyValuePair, "get_Value", typesOfArguments)); var targetKey = NewVariable(typesOfArguments[0]); list.AddRange(Copy(typesOfArguments[0], sourceKey, ValueTarget.New().Variable(targetKey))); var targetValue = NewVariable(typesOfArguments[1]); list.AddRange(Copy(typesOfArguments[1], sourceValue, ValueTarget.New().Variable(targetValue))); list.Add(variable?.CreateLoadInstruction() ?? Instruction.Create(OpCodes.Ldarg_0)); list.Add(targetKey.CreateLoadInstruction()); list.Add(targetValue.CreateLoadInstruction()); list.Add(Instruction.Create(OpCodes.Callvirt, ImportMethod(type.Resolve(), "set_Item", typesOfArguments))); } if (!target.IsTargetingBase) { list.AddRange(target.Build(ValueSource.New().Variable(variable))); } } return(list); }