Permalink
Browse files

Fix for issue #191 Cannot convert enum to nullable int

  • Loading branch information...
dvorobiov authored and jbogard committed Apr 8, 2012
1 parent 54cdf53 commit 19f0cb7b2064b7623fc5164729b2fe7be808603b
Showing with 180 additions and 117 deletions.
  1. +143 −117 src/AutoMapper/Mappers/EnumMapper.cs
  2. +36 −0 src/UnitTests/Bug/CannotConvertEnumToNullable.cs
  3. +1 −0 src/UnitTests/UnitTests.csproj
@@ -1,118 +1,144 @@
using System;
using System.Linq;
namespace AutoMapper.Mappers
{
public class EnumMapper : IObjectMapper
{
public object Map(ResolutionContext context, IMappingEngineRunner mapper)
{
bool toEnum = false;
Type enumSourceType = TypeHelper.GetEnumerationType(context.SourceType);
Type enumDestinationType = TypeHelper.GetEnumerationType(context.DestinationType);
if (EnumToStringMapping(context, ref toEnum))
{
if (context.SourceValue == null)
{
return mapper.CreateObject(context);
}
if (toEnum)
{
var stringValue = context.SourceValue.ToString();
if (string.IsNullOrEmpty(stringValue))
{
return mapper.CreateObject(context);
}
return Enum.Parse(enumDestinationType, stringValue, true);
}
return Enum.GetName(enumSourceType, context.SourceValue);
}
if (EnumToEnumMapping(context))
{
if (context.SourceValue == null)
{
return mapper.CreateObject(context);
}
if (!Enum.IsDefined(enumSourceType, context.SourceValue))
{
return Enum.ToObject(enumDestinationType, context.SourceValue);
}
#if !SILVERLIGHT
if (!Enum.GetNames(enumDestinationType).Contains(context.SourceValue.ToString()))
{
Type underlyingSourceType = Enum.GetUnderlyingType(enumSourceType);
var underlyingSourceValue = Convert.ChangeType(context.SourceValue, underlyingSourceType);
return Enum.ToObject(context.DestinationType, underlyingSourceValue);
}
#endif
return Enum.Parse(enumDestinationType, Enum.GetName(enumSourceType, context.SourceValue), true);
}
if (EnumToUnderlyingTypeMapping(context, ref toEnum))
{
if (toEnum)
{
return Enum.Parse(enumDestinationType, context.SourceValue.ToString(), true);
}
return Convert.ChangeType(context.SourceValue, context.DestinationType, null);
}
return null;
}
public bool IsMatch(ResolutionContext context)
{
bool toEnum = false;
return EnumToStringMapping(context, ref toEnum) || EnumToEnumMapping(context) || EnumToUnderlyingTypeMapping(context, ref toEnum);
}
private static bool EnumToEnumMapping(ResolutionContext context)
{
// Enum to enum mapping
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
return sourceEnumType != null && destEnumType != null;
}
private static bool EnumToUnderlyingTypeMapping(ResolutionContext context, ref bool toEnum)
{
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
// Enum to underlying type
if (sourceEnumType != null)
{
return context.DestinationType.IsAssignableFrom(Enum.GetUnderlyingType(sourceEnumType));
}
if (destEnumType != null)
{
toEnum = true;
return context.SourceType.IsAssignableFrom(Enum.GetUnderlyingType(destEnumType));
}
return false;
}
private static bool EnumToStringMapping(ResolutionContext context, ref bool toEnum)
{
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
// Enum to string
if (sourceEnumType != null)
{
return context.DestinationType.IsAssignableFrom(typeof(string));
}
if (destEnumType != null)
{
toEnum = true;
return context.SourceType.IsAssignableFrom(typeof(string));
}
return false;
}
}
using System;
using System.ComponentModel;
using System.Linq;
namespace AutoMapper.Mappers
{
public class EnumMapper : IObjectMapper
{
public object Map(ResolutionContext context, IMappingEngineRunner mapper)
{
bool toEnum = false;
Type enumSourceType = TypeHelper.GetEnumerationType(context.SourceType);
Type enumDestinationType = TypeHelper.GetEnumerationType(context.DestinationType);
if (EnumToStringMapping(context, ref toEnum))
{
if (context.SourceValue == null)
{
return mapper.CreateObject(context);
}
if (toEnum)
{
var stringValue = context.SourceValue.ToString();
if (string.IsNullOrEmpty(stringValue))
{
return mapper.CreateObject(context);
}
return Enum.Parse(enumDestinationType, stringValue, true);
}
return Enum.GetName(enumSourceType, context.SourceValue);
}
if (EnumToEnumMapping(context))
{
if (context.SourceValue == null)
{
return mapper.CreateObject(context);
}
if (!Enum.IsDefined(enumSourceType, context.SourceValue))
{
return Enum.ToObject(enumDestinationType, context.SourceValue);
}
#if !SILVERLIGHT
if (!Enum.GetNames(enumDestinationType).Contains(context.SourceValue.ToString()))
{
Type underlyingSourceType = Enum.GetUnderlyingType(enumSourceType);
var underlyingSourceValue = Convert.ChangeType(context.SourceValue, underlyingSourceType);
return Enum.ToObject(context.DestinationType, underlyingSourceValue);
}
#endif
return Enum.Parse(enumDestinationType, Enum.GetName(enumSourceType, context.SourceValue), true);
}
if (EnumToUnderlyingTypeMapping(context, ref toEnum))
{
if (toEnum)
{
return Enum.Parse(enumDestinationType, context.SourceValue.ToString(), true);
}
if (EnumToNullableTypeMapping(context))
{
return ConvertEnumToNullableType(context);
}
return Convert.ChangeType(context.SourceValue, context.DestinationType, null);
}
return null;
}
public bool IsMatch(ResolutionContext context)
{
bool toEnum = false;
return EnumToStringMapping(context, ref toEnum) || EnumToEnumMapping(context) || EnumToUnderlyingTypeMapping(context, ref toEnum);
}
private static bool EnumToEnumMapping(ResolutionContext context)
{
// Enum to enum mapping
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
return sourceEnumType != null && destEnumType != null;
}
private static bool EnumToUnderlyingTypeMapping(ResolutionContext context, ref bool toEnum)
{
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
// Enum to underlying type
if (sourceEnumType != null)
{
return context.DestinationType.IsAssignableFrom(Enum.GetUnderlyingType(sourceEnumType));
}
if (destEnumType != null)
{
toEnum = true;
return context.SourceType.IsAssignableFrom(Enum.GetUnderlyingType(destEnumType));
}
return false;
}
private static bool EnumToStringMapping(ResolutionContext context, ref bool toEnum)
{
var sourceEnumType = TypeHelper.GetEnumerationType(context.SourceType);
var destEnumType = TypeHelper.GetEnumerationType(context.DestinationType);
// Enum to string
if (sourceEnumType != null)
{
return context.DestinationType.IsAssignableFrom(typeof(string));
}
if (destEnumType != null)
{
toEnum = true;
return context.SourceType.IsAssignableFrom(typeof(string));
}
return false;
}
private static bool EnumToNullableTypeMapping(ResolutionContext context)
{
if (!context.DestinationType.IsGenericType)
{
return false;
}
var genericType = context.DestinationType.GetGenericTypeDefinition();
return genericType.Equals(typeof(Nullable<>));
}
private static object ConvertEnumToNullableType(ResolutionContext context)
{
var nullableConverter = new NullableConverter(context.DestinationType);
var destType = nullableConverter.UnderlyingType;
return Convert.ChangeType(context.SourceValue, destType);
}
}
}
@@ -0,0 +1,36 @@
using NUnit.Framework;
namespace AutoMapper.UnitTests.Bug
{
[TestFixture]
public class CannotConvertEnumToNullable
{
public enum DummyTypes : int
{
Foo = 1,
Bar = 2
}
public class DummySource
{
public DummyTypes Dummy { get; set; }
}
public class DummyDestination
{
public int? Dummy { get; set; }
}
[Test]
public void Should_map_enum_to_nullable()
{
Mapper.CreateMap<DummySource, DummyDestination>();
Mapper.AssertConfigurationIsValid();
DummySource src = new DummySource() { Dummy = DummyTypes.Bar };
var destination = Mapper.Map<DummySource, DummyDestination>(src);
Assert.AreEqual((int)DummyTypes.Bar, destination.Dummy);
}
}
}
@@ -107,6 +107,7 @@
<Compile Include="Bug\AllMembersNullSubstitute.cs" />
<Compile Include="Bug\AllowNullDestinationValuesBugs.cs" />
<Compile Include="Bug\AssignableCollectionBug.cs" />
<Compile Include="Bug\CannotConvertEnumToNullable.cs" />
<Compile Include="Bug\CollectionMapperMapsISetIncorrectly.cs" />
<Compile Include="Bug\CustomIEnumerableBug.cs" />
<Compile Include="Bug\AddingConfigurationForNonMatchingDestinationMemberBug.cs" />

0 comments on commit 19f0cb7

Please sign in to comment.