Exemple #1
0
        /// <summary>
        ///     Returns the widener.
        /// </summary>
        /// <param name="columnName">name of column</param>
        /// <param name="columnType">type of column</param>
        /// <param name="writeablePropertyType">property type</param>
        /// <param name="writeablePropertyName">propery name</param>
        /// <param name="allowObjectArrayToCollectionConversion">whether we widen object-array to collection</param>
        /// <param name="customizer">customization if any</param>
        /// <param name="statementName">statement name</param>
        /// <returns>type widener</returns>
        /// <throws>TypeWidenerException if type validation fails</throws>
        public static TypeWidenerSPI GetCheckPropertyAssignType(
            string columnName,
            Type columnType,
            Type writeablePropertyType,
            string writeablePropertyName,
            bool allowObjectArrayToCollectionConversion,
            TypeWidenerCustomizer customizer,
            string statementName)
        {
            var columnTypeBoxed = columnType.GetBoxedType();
            var targetTypeBoxed = writeablePropertyType.GetBoxedType();

            var custom = customizer?.WidenerFor(
                columnName,
                columnType,
                writeablePropertyType,
                writeablePropertyName,
                statementName);
            if (custom != null) {
                return custom;
            }

            if (columnType == null) {
                if (writeablePropertyType.CanNotBeNull()) {
                    var message = "Invalid assignment of column '" +
                                  columnName +
                                  "' of null type to event property '" +
                                  writeablePropertyName +
                                  "' typed as '" +
                                  writeablePropertyType.CleanName() +
                                  "', nullable type mismatch";
                    throw new TypeWidenerException(message);
                }
            }
            else if (columnTypeBoxed != targetTypeBoxed) {
                if (columnTypeBoxed == typeof(string) && targetTypeBoxed == typeof(char?)) {
                    return STRING_TO_CHAR_COERCER;
                }

                if (allowObjectArrayToCollectionConversion &&
                    columnTypeBoxed.IsArray &&
                    !columnTypeBoxed.GetElementType().IsValueType &&
                    targetTypeBoxed.IsImplementsInterface(typeof(ICollection<object>))) {
                    return OBJECT_ARRAY_TO_COLLECTION_COERCER;
                }
                
                // Boxed types tend to be incompatible from an assignment perspective.  We have both
                // the boxed and unboxed values.  The problem is that the boxed values will always
                // be unboxed prior to assignment, so looking for assignment of boxed types is not
                // a winning approach.

                var columnTypeUnboxed = columnType.GetUnboxedType();
                var targetTypeUnboxed = targetTypeBoxed.GetUnboxedType();

                if (!columnType.IsAssignmentCompatible(writeablePropertyType) && 
                    !columnTypeUnboxed.IsAssignmentCompatible(targetTypeUnboxed)) {
                    
                    // Arrays can be assigned to each other if the underlying target types
                    // can be assigned from one another.
                    if (columnType.IsArray && 
                        targetTypeBoxed.IsArray &&
                        columnType.GetArrayRank() == targetTypeBoxed.GetArrayRank()) {
                        var columnElementType = columnType.GetElementType();
                        var targetElementType = targetTypeBoxed.GetElementType();
                        if (columnElementType.IsAssignmentCompatible(targetElementType)) {
                            return new TypeWidenerCompatibleArrayCoercer(
                                columnElementType,
                                targetElementType);
                        }
                    }

                    var writablePropName = writeablePropertyType.CleanName();
                    if (writeablePropertyType.IsArray) {
                        writablePropName = writeablePropertyType.GetElementType().CleanName() + "[]";
                    }

                    var columnTypeName = columnType.CleanName();
                    if (columnType.IsArray) {
                        columnTypeName = columnType.GetElementType().CleanName() + "[]";
                    }

                    var message = "Invalid assignment of column '" +
                                  columnName +
                                  "' of type '" +
                                  columnTypeName +
                                  "' to event property '" +
                                  writeablePropertyName +
                                  "' typed as '" +
                                  writablePropName +
                                  "', column and parameter types mismatch";
                    throw new TypeWidenerException(message);
                }

                if (writeablePropertyType.IsNumeric()) {
                    return new TypeWidenerBoxedNumeric(
                        SimpleNumberCoercerFactory.GetCoercer(columnTypeBoxed, targetTypeBoxed));
                }
            }

            return null;
        }
Exemple #2
0
        /// <summary>Returns the widener. </summary>
        /// <param name="columnName">name of column</param>
        /// <param name="columnType">type of column</param>
        /// <param name="writeablePropertyType">property type</param>
        /// <param name="writeablePropertyName">propery name</param>
        /// <param name="allowObjectArrayToCollectionConversion">whether we widen object-array to collection</param>
        /// <param name="customizer">customization if any</param>
        /// <param name="engineURI">engine URI</param>
        /// <param name="statementName">statement name</param>
        /// <exception cref="ExprValidationException">if type validation fails</exception>
        /// <returns>type widender</returns>
        /// <throws>ExprValidationException if type validation fails</throws>
        public static TypeWidener GetCheckPropertyAssignType(
            String columnName,
            Type columnType,
            Type writeablePropertyType,
            String writeablePropertyName,
            bool allowObjectArrayToCollectionConversion,
            TypeWidenerCustomizer customizer,
            string statementName,
            string engineURI)
        {
            Type columnClassBoxed = TypeHelper.GetBoxedType(columnType);
            Type targetClassBoxed = TypeHelper.GetBoxedType(writeablePropertyType);

            if (customizer != null)
            {
                TypeWidener custom = customizer.WidenerFor(columnName, columnType, writeablePropertyType, writeablePropertyName, statementName, engineURI);
                if (custom != null)
                {
                    return(custom);
                }
            }

            if (columnType == null)
            {
                if (writeablePropertyType.IsPrimitive)
                {
                    String message = "Invalid assignment of column '" + columnName +
                                     "' of null type to event property '" + writeablePropertyName +
                                     "' typed as '" + writeablePropertyType.FullName +
                                     "', nullable type mismatch";
                    throw new ExprValidationException(message);
                }
            }
            else if (columnClassBoxed != targetClassBoxed)
            {
                if (columnClassBoxed == typeof(string) && targetClassBoxed == typeof(char?))
                {
                    return(TypeWidenerStringToCharCoercer.Widen);
                }

                if (allowObjectArrayToCollectionConversion &&
                    columnClassBoxed.IsArray &&
                    !columnClassBoxed.GetElementType().IsPrimitive &&
                    targetClassBoxed.IsGenericCollection())
                {
                    return(OBJECT_ARRAY_TO_COLLECTION_COERCER);
                }

                if (columnClassBoxed.IsGenericDictionary() && targetClassBoxed.IsGenericDictionary())
                {
                    var columnClassGenerics = columnClassBoxed.GetGenericArguments();
                    var targetClassGenerics = targetClassBoxed.GetGenericArguments();
                    var transformMethod     = typeof(TransformDictionaryFactory)
                                              .GetMethod("Create", new[] { typeof(object) })
                                              .MakeGenericMethod(targetClassGenerics[0], targetClassGenerics[1], columnClassGenerics[0], columnClassGenerics[1]);

                    return(source =>
                    {
                        var parameters = new object[] { source };
                        return transformMethod.Invoke(null, BindingFlags.Static | BindingFlags.Public, null, parameters, null);
                    });
                }

                if ((columnClassBoxed == typeof(string)) &&
                    (targetClassBoxed == typeof(char[])))
                {
                    return(source =>
                    {
                        var sourceAsString = (string)source;
                        return sourceAsString != null?sourceAsString.ToCharArray() : null;
                    });
                }

                if ((columnClassBoxed == typeof(char[])) &&
                    (targetClassBoxed == typeof(string)))
                {
                    return(source =>
                    {
                        var sourceAsCharArray = (char[])source;
                        return sourceAsCharArray != null ? new string(sourceAsCharArray) : null;
                    });
                }

                if (columnClassBoxed.IsArray && targetClassBoxed.IsArray)
                {
                    var columnClassElement = columnClassBoxed.GetElementType();
                    var targetClassElement = targetClassBoxed.GetElementType();
                    if (columnClassElement.IsAssignmentCompatible(targetClassElement))
                    {
                        // By definition, columnClassElement and targetClassElement should be
                        // incompatible.  Question is, can we find a coercer between them?
                        var coercer = CoercerFactory.GetCoercer(columnClassElement, targetClassElement);
                        return(source => WidenArray(source, targetClassElement, coercer));
                    }
                }

                if (!columnClassBoxed.IsAssignmentCompatible(targetClassBoxed))
                {
                    var writablePropName = writeablePropertyType.FullName;
                    if (writeablePropertyType.IsArray)
                    {
                        writablePropName = writeablePropertyType.GetElementType().FullName + "[]";
                    }

                    var columnTypeName = columnType.FullName;
                    if (columnType.IsArray)
                    {
                        columnTypeName = columnType.GetElementType().FullName + "[]";
                    }

                    String message = "Invalid assignment of column '" + columnName +
                                     "' of type '" + columnTypeName +
                                     "' to event property '" + writeablePropertyName +
                                     "' typed as '" + writablePropName +
                                     "', column and parameter types mismatch";
                    throw new ExprValidationException(message);
                }

                if (writeablePropertyType.IsNumeric())
                {
                    var instance = new TypeWidenerBoxedNumeric(
                        CoercerFactory.GetCoercer(columnClassBoxed, targetClassBoxed));
                    return(instance.Widen);
                }
            }

            return(null);
        }