Skip to content

Commit

Permalink
Fix for issue #191 Cannot convert enum to nullable int
Browse files Browse the repository at this point in the history
  • Loading branch information
dvorobiov authored and jbogard committed Apr 20, 2012
1 parent 54cdf53 commit 19f0cb7
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 117 deletions.
260 changes: 143 additions & 117 deletions src/AutoMapper/Mappers/EnumMapper.cs
Original file line number Diff line number Diff line change
@@ -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);
}

}
}
36 changes: 36 additions & 0 deletions src/UnitTests/Bug/CannotConvertEnumToNullable.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
1 change: 1 addition & 0 deletions src/UnitTests/UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down

0 comments on commit 19f0cb7

Please sign in to comment.