Exemplo n.º 1
0
 public override void Emit(Type sourceType, Type targetType, CompilationContext context)
 {
     context.LoadSource(LoadPurpose.Parameter);
     context.CurrentType = sourceType;
     context.EmitCast(typeof(IEnumerable <>).MakeGenericType(_sourceElementType));
     context.LoadTarget(LoadPurpose.Parameter);
     context.CurrentType = targetType;
     context.EmitCast(typeof(IEnumerable <>).MakeGenericType(_targetElementType));
     _invokerBuilder.Emit(context);
 }
Exemplo n.º 2
0
        public override void Emit(Type sourceType, Type targetType, CompilationContext context)
        {
            var reflectingTargetType = targetType.GetTypeInfo();

            context.EmitCast(typeof(IEnumerable <>).MakeGenericType(_sourceElementType));
            _invokerBuilder.Emit(context);
            if (reflectingTargetType.IsGenericType)
            {
                var genericTypeDefinition = targetType.GetGenericTypeDefinition();
                if (genericTypeDefinition == typeof(IList <>) || genericTypeDefinition == typeof(ICollection <>) || genericTypeDefinition == typeof(IEnumerable <>))
                {
                    context.EmitCast(targetType);
                    return;
                }
            }
            else if (targetType.IsArray)
            {
                context.EmitCast(targetType);
                return;
            }
            if (targetType.IsEnumerable(out var targetElementType))
            {
                var constructor = reflectingTargetType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { typeof(IList <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { typeof(ICollection <>).MakeGenericType(targetElementType) }) ??
                                  reflectingTargetType.GetConstructor(new[] { targetElementType.MakeArrayType() });
                if (constructor != null)
                {
                    context.EmitCast(constructor.GetParameters()[0].ParameterType);
                    context.Emit(OpCodes.Newobj, constructor);
                    context.CurrentType = targetType;
                }
                else
                {
                    var defaultConstructor = reflectingTargetType.GetConstructor(Type.EmptyTypes);
                    var addMethod          = reflectingTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(method =>
                    {
                        if (method.Name != "Add")
                        {
                            return(false);
                        }
                        var parameters = method.GetParameters();
                        return(parameters.Length == 1 && parameters[0].ParameterType == targetElementType);
                    }).FirstOrDefault();
                    if (defaultConstructor != null && addMethod != null)
                    {
                        var targetArrayType = targetElementType.MakeArrayType();
                        var targetArray     = context.DeclareLocal(targetArrayType);
                        var targetInstance  = context.DeclareLocal(targetType);
                        var index           = context.DeclareLocal(typeof(int));

                        context.EmitCast(targetArrayType);
                        context.Emit(OpCodes.Stloc, targetArray);

                        context.Emit(OpCodes.Newobj, defaultConstructor);
                        context.Emit(OpCodes.Stloc, targetInstance);

                        // var i = 0;
                        context.Emit(OpCodes.Ldc_I4_0);
                        context.Emit(OpCodes.Stloc, index);

                        var labelEnd = context.DefineLabel();
                        context.Emit(OpCodes.Br_S, labelEnd);
                        var labelStart = context.DefineLabel();
                        context.MakeLabel(labelStart);

                        // target.Add(array[i]);
                        context.Emit(OpCodes.Ldloc, targetInstance);
                        context.Emit(OpCodes.Ldloc, targetArray);
                        context.Emit(OpCodes.Ldloc, index);
                        var targetElementTypeInfo = targetElementType.GetTypeInfo();
                        if (targetElementTypeInfo.IsValueType && !targetElementTypeInfo.IsPrimitive)
                        {
                            context.Emit(OpCodes.Ldelema, targetElementType);
                        }
                        else
                        {
                            context.Emit(OpCodes.Ldelem, targetElementType);
                        }
                        context.EmitCall(addMethod);

                        // i++
                        context.Emit(OpCodes.Ldloc, index);
                        context.Emit(OpCodes.Ldc_I4_1);
                        context.Emit(OpCodes.Add);
                        context.Emit(OpCodes.Stloc, index);


                        context.MakeLabel(labelEnd);
                        context.Emit(OpCodes.Ldloc, index);
                        context.Emit(OpCodes.Ldloc, targetArray);
                        context.Emit(OpCodes.Ldlen);
                        context.Emit(OpCodes.Conv_I4);
                        context.Emit(OpCodes.Blt_S, labelStart);

                        context.Emit(OpCodes.Ldloc, targetInstance);
                        context.CurrentType = targetType;
                    }
                }
            }
        }