예제 #1
0
        /// <summary>
        /// Register a manual mapping information from source to target
        /// </summary>
        /// <typeparam name="TSource">Source type</typeparam>
        /// <typeparam name="TTarget">Target type</typeparam>
        public void RegisterMap <TSource, TTarget>(Action <TSource, TTarget> convert)
        {
            var sourceType = typeof(TSource);
            var targetType = typeof(TTarget);

            if (!_mappings.ContainsKey(sourceType))
            {
                _mappings[sourceType] = new Dictionary <Type, ILMappingInfo>();
            }

            ILMappingInfo ilMappingInfo = _mappings[sourceType].ContainsKey(targetType)
                ? _mappings[sourceType][targetType]
                : new IlMappingInfo <TSource, TTarget>();

            ilMappingInfo.ManualMapper        = (s, t) => convert((TSource)s, (TTarget)t);
            ilMappingInfo.InstanceMapper      = (s, t) => convert((TSource)s, (TTarget)t);
            _mappings[sourceType][targetType] = ilMappingInfo;
        }
예제 #2
0
        /// <summary>
        /// Generate dynamic method for collection mapping
        /// </summary>
        Func <ILMappingInfo, IList <TSource>, TTarget[]> GenerateCollectionDelegate <TSource, TTarget>(List <PropertyMapper> properties, ILMappingInfo ilMappingInfo)
        {
            var sourceType           = typeof(TSource);
            var targetType           = typeof(TTarget);
            var targetCollectionType = typeof(TTarget[]);

            var targetConstrucotr = targetType.GetConstructor(Type.EmptyTypes);

            if (targetConstrucotr == null)
            {
                throw new ArgumentException("Target type must have a parameterless constructor");
            }


            var targetCollectionConstrucotr = targetCollectionType.GetConstructor(new[] { typeof(int) });

            if (targetCollectionConstrucotr == null)
            {
                throw new ArgumentException();
            }

            var dm = new DynamicMethod($"_MAP_LIST_{sourceType.Name}_{targetType.Name}",
                                       typeof(TTarget[]),
                                       new[] { typeof(ILMappingInfo), typeof(IList <TSource>) },
                                       typeof(TTarget).GetTypeInfo().Module);
            var il = dm.GetILGenerator();


            var loopStart = il.DefineLabel();
            var loopExit  = il.DefineLabel();


            // Store argument list in local
            var mappingInfoLocal = il.DeclareLocal(typeof(ILMappingInfo));
            var source           = il.DeclareLocal(typeof(IList <TSource>));
            var result           = il.DeclareLocal(typeof(TTarget[]));
            var count            = il.DeclareLocal(typeof(IList <TSource>));
            var index            = il.DeclareLocal(typeof(IList <TSource>));
            var sourceItem       = il.DeclareLocal(typeof(TSource));
            var targetItem       = il.DeclareLocal(typeof(TTarget));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, mappingInfoLocal);

            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Stloc, source);

            // Define result array
            ;
            il.Emit(OpCodes.Ldloc, source);
            il.Emit(OpCodes.Call, typeof(ICollection).GetMethod("get_Count"));
            il.Emit(OpCodes.Stloc, count);
            il.Emit(OpCodes.Ldloc, count);
            il.Emit(OpCodes.Newarr, typeof(TTarget));
            il.Emit(OpCodes.Stloc, result);

            il.Emit(OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Stloc, index);


            // Mark loop start
            il.MarkLabel(loopStart);


            //Get item at index
            il.Emit(OpCodes.Ldloc, source);
            il.Emit(OpCodes.Ldloc, index);
            il.Emit(OpCodes.Call, typeof(IList <TSource>).GetMethod("get_Item"));
            il.Emit(OpCodes.Stloc, sourceItem);


            // Create new item
            il.Emit(OpCodes.Newobj, targetConstrucotr);
            il.Emit(OpCodes.Stloc, targetItem);


            // Map properties
            foreach (var property in properties)
            {
                EmitPropertyMap(property, il, sourceItem, targetItem);
            }


            if (ilMappingInfo.AdditionalMap != null)
            {
                var method = ilMappingInfo.GetType().GetMethod(nameof(ILMappingInfo.ExecuteAdditionalMap));
                if (method != null)
                {
                    il.Emit(OpCodes.Ldloc, mappingInfoLocal);
                    il.Emit(OpCodes.Ldloc, sourceItem);
                    il.Emit(OpCodes.Ldloc, targetItem);
                    il.Emit(OpCodes.Call, method);
                }
            }

            // Add item to list
            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Ldloc, index);
            il.Emit(OpCodes.Ldloc, targetItem);
            il.Emit(OpCodes.Stelem_Ref);

            // increment index
            il.Emit(OpCodes.Ldloc, index);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Stloc, index);

            // Check loop end
            il.Emit(OpCodes.Ldloc, index);
            il.Emit(OpCodes.Ldloc, count);
            il.Emit(OpCodes.Beq, loopExit);

            // Repeat
            il.Emit(OpCodes.Br, loopStart);

            il.MarkLabel(loopExit);

            il.Emit(OpCodes.Ldloc, result);
            il.Emit(OpCodes.Ret);

            return((Func <ILMappingInfo, IList <TSource>, TTarget[]>)dm.CreateDelegate(typeof(Func <ILMappingInfo, IList <TSource>, TTarget[]>)));
        }