public void TestGetCoercer() { Assert.AreEqual(1d, SimpleNumberCoercerFactory.GetCoercer(null, typeof(double?)).CoerceBoxed(1d)); Assert.AreEqual(1d, SimpleNumberCoercerFactory.GetCoercer(typeof(double?), typeof(double?)).CoerceBoxed(1d)); Assert.AreEqual(5d, SimpleNumberCoercerFactory.GetCoercer(typeof(int?), typeof(double?)).CoerceBoxed(5)); Assert.AreEqual(6d, SimpleNumberCoercerFactory.GetCoercer(typeof(byte?), typeof(double?)).CoerceBoxed((byte)6)); Assert.AreEqual(3f, SimpleNumberCoercerFactory.GetCoercer(typeof(long?), typeof(float?)).CoerceBoxed((long)3)); Assert.AreEqual((short)2, SimpleNumberCoercerFactory.GetCoercer(typeof(long?), typeof(short?)).CoerceBoxed((long)2)); Assert.AreEqual(4, SimpleNumberCoercerFactory.GetCoercer(typeof(long?), typeof(int?)).CoerceBoxed((long)4)); Assert.AreEqual((byte)5, SimpleNumberCoercerFactory.GetCoercer(typeof(long?), typeof(byte?)).CoerceBoxed((long)5)); Assert.AreEqual(8l, SimpleNumberCoercerFactory.GetCoercer(typeof(long?), typeof(long?)).CoerceBoxed((long)8)); Assert.AreEqual(new BigInteger(8), SimpleNumberCoercerFactory.GetCoercer(typeof(int), typeof(BigInteger)).CoerceBoxed(8)); Assert.AreEqual(9m, SimpleNumberCoercerFactory.GetCoercer(typeof(int), typeof(decimal?)).CoerceBoxed(9)); Assert.AreEqual(9m, SimpleNumberCoercerFactory.GetCoercer(typeof(double), typeof(decimal?)).CoerceBoxed(9.0)); Assert.AreEqual(9.0m, SimpleNumberCoercerFactory.GetCoercer(typeof(double), typeof(decimal?)).CoerceBoxed(9.0)); Assert.AreEqual(9m, SimpleNumberCoercerFactory.GetCoercer(typeof(long), typeof(decimal?)).CoerceBoxed(9)); Assert.AreEqual(10m, SimpleNumberCoercerFactory.GetCoercer(typeof(decimal), typeof(decimal?)).CoerceBoxed(10m)); Assert.AreEqual(new BigInteger(9), SimpleNumberCoercerFactory.GetCoercerBigInteger(typeof(long)).CoerceBoxedBigInt(9)); Assert.AreEqual(new BigInteger(10), SimpleNumberCoercerFactory.GetCoercerBigInteger(typeof(BigInteger)).CoerceBoxedBigInt(new BigInteger(10))); //Assert.Throws<ArgumentException>(() => TypeHelper.CoerceBoxed(10, typeof(int))); }
/// <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; }