Esempio n. 1
0
        /// <summary>
        /// Binds 'cast' function to create a LINQ <see cref="Expression"/>.
        /// </summary>
        /// <param name="node">The query node to bind.</param>
        /// <param name="context">The query binder context.</param>
        /// <returns>The LINQ <see cref="Expression"/> created.</returns>
        protected virtual Expression BindCastSingleValue(SingleValueFunctionCallNode node, QueryBinderContext context)
        {
            CheckArgumentNull(node, context, "cast");

            Expression[] arguments = BindArguments(node.Parameters, context);
            Contract.Assert(arguments.Length == 1 || arguments.Length == 2);

            Expression source         = arguments.Length == 1 ? context.CurrentParameter : arguments[0];
            string     targetTypeName = (string)((ConstantNode)node.Parameters.Last()).Value;
            IEdmType   targetEdmType  = context.Model.FindType(targetTypeName);
            Type       targetClrType  = null;

            if (targetEdmType != null)
            {
                IEdmTypeReference targetEdmTypeReference = targetEdmType.ToEdmTypeReference(false);
                targetClrType = context.Model.GetClrType(targetEdmTypeReference);

                if (source != NullConstant)
                {
                    if (source.Type == targetClrType)
                    {
                        return(source);
                    }

                    if ((!targetEdmTypeReference.IsPrimitive() && !targetEdmTypeReference.IsEnum()) ||
                        (context.Model.GetEdmPrimitiveTypeReference(source.Type) == null && !TypeHelper.IsEnum(source.Type)))
                    {
                        // Cast fails and return null.
                        return(NullConstant);
                    }
                }
            }

            if (targetClrType == null || source == NullConstant)
            {
                return(NullConstant);
            }

            if (targetClrType == typeof(string))
            {
                return(ExpressionBinderHelper.BindCastToStringType(source));
            }
            else if (TypeHelper.IsEnum(targetClrType))
            {
                return(BindCastToEnumType(source.Type, targetClrType, node.Parameters.First(), arguments.Length, context));
            }
            else
            {
                if (TypeHelper.IsNullable(source.Type) && !TypeHelper.IsNullable(targetClrType))
                {
                    // Make the target Clr type nullable to avoid failure while casting
                    // nullable source, whose value may be null, to a non-nullable type.
                    // For example: cast(NullableInt32Property,Edm.Int64)
                    // The target Clr type should be Nullable<Int64> rather than Int64.
                    targetClrType = typeof(Nullable <>).MakeGenericType(targetClrType);
                }

                try
                {
                    return(Expression.Convert(source, targetClrType));
                }
                catch (InvalidOperationException)
                {
                    // Cast fails and return null.
                    return(NullConstant);
                }
            }
        }