Esempio n. 1
0
        private static Func <Closure, object> Convert(UnaryExpression convertExpression,
                                                      ConstantExpression[] constantsExprs, ParameterExpression[] localsExprs)
        {
            var valueFn         = Expression(convertExpression.Operand, constantsExprs, localsExprs);
            var convertOperator = WrapUnaryOperation(convertExpression.Method) ?? WrapUnaryOperation(
                convertExpression.Type
                .GetMethods(BindingFlags.Public | BindingFlags.Static)
                .FirstOrDefault(m =>
                                (string.Equals(m.Name, "op_Explicit", StringComparison.Ordinal) || string.Equals(m.Name, "op_Implicit", StringComparison.Ordinal)) &&
                                m.ReturnType == convertExpression.Type &&
                                m.GetParameters().Length == 1 &&
                                m.GetParameters()[0].ParameterType == convertExpression.Operand.Type)
                );
            var toType         = Nullable.GetUnderlyingType(convertExpression.Type) ?? convertExpression.Type;
            var toIsNullable   = Nullable.GetUnderlyingType(convertExpression.Type) != null;
            var fromType       = Nullable.GetUnderlyingType(convertExpression.Operand.Type) ?? convertExpression.Operand.Type;
            var fromIsNullable = IsNullable(convertExpression.Operand);

            return(closure =>
            {
                var value = closure.Unbox <object>(valueFn(closure));
                if (value == null && (convertExpression.Type.IsValueType == false || toIsNullable))
                {
                    return null;
                }

                var convertType = convertExpression.NodeType;
                if (convertType != ExpressionType.Convert)
                {
                    convertType = ExpressionType.ConvertChecked;
                }

                // un-box
                if ((fromType == typeof(object) || fromType == typeof(ValueType) || fromType.IsInterface) && toType.IsValueType)
                {
                    // null un-box
                    if (value == null)
                    {
                        throw new NullReferenceException("Attempt to unbox a null value.");
                    }
                    // typecheck for un-box
                    if (value.GetType() == toType)
                    {
                        return value;
                    }
                    throw new InvalidCastException();
                }
                // box
                else if (fromType.IsValueType && (toType == typeof(object) || toType == typeof(ValueType) || toType.IsInterface))
                {
                    // typecheck for box
                    return toType.IsAssignableFrom(value.GetType()) ? value : null;
                }
                // to enum
                else if (toType.IsEnum && (fromType == typeof(byte) || fromType == typeof(sbyte) ||
                                           fromType == typeof(short) || fromType == typeof(ushort) ||
                                           fromType == typeof(int) || fromType == typeof(uint) ||
                                           fromType == typeof(long) || fromType == typeof(ulong)))
                {
                    if (value == null)
                    {
                        throw new NullReferenceException("Attempt to unbox a null value.");
                    }

                    value = Intrinsics.Convert(closure, value, Enum.GetUnderlyingType(toType), convertExpression.NodeType, null);
                    return Enum.ToObject(toType, closure.Unbox <object>(value));
                }
                // from enum
                else if (fromType.IsEnum && (toType == typeof(byte) || toType == typeof(sbyte) ||
                                             toType == typeof(short) || toType == typeof(ushort) ||
                                             toType == typeof(int) || toType == typeof(uint) ||
                                             toType == typeof(long) || toType == typeof(ulong)))
                {
                    if (value == null)
                    {
                        throw new NullReferenceException("Attempt to unbox a null value.");
                    }

                    value = System.Convert.ChangeType(value, Enum.GetUnderlyingType(fromType));
                    value = Intrinsics.Convert(closure, value, toType, convertExpression.NodeType, null);
                    return value;
                }
                // from nullable
                if (toType.IsValueType && fromIsNullable)
                {
                    if (value == null)
                    {
                        throw new NullReferenceException("Attempt to unbox a null value.");
                    }

                    value = Intrinsics.Convert(closure, value, Nullable.GetUnderlyingType(toType) ?? toType, convertExpression.NodeType, null);
                }
                else if (toType.IsAssignableFrom(fromType))
                {
                    return value;
                }

                return Intrinsics.Convert(closure, value, toType, convertType, convertOperator);
            });
        }