The default list mapping almost works for mapping between say
IPageOf<UserDomainModel> and IPageOf<UserViewModel> but AutoMapper by
default doesnt' know how to instantiate the destination generic type
without using generics.
Is there a way to define a custom object mapper that can provide a
generic mapping for this?
Thanks,
CV
I took another look at this problem today and decided to copy
EnumerableMapperBase
which brought me to this
public class PageOfMapper : IObjectMapper
{
private static Type IPageOfType = typeof(IPageOf);
private static bool IsPageOfType(Type type)
{
return type.GetInterfaces().Contains(IPageOfType);
}
public bool IsMatch(ResolutionContext context)
{
return IsPageOfType(context.DestinationType) &&
IsPageOfType(context.SourceType);
}
public object Map(ResolutionContext context,
IMappingEngineRunner mapper)
{
if
(context.DestinationType.IsAssignableFrom(context.SourceType) &&
context.SourceValue != null)
{
return context.SourceValue;
}
//
// turn the source value into a bunch of useful forms
//
var sourceValue = (IEnumerable)context.SourceValue ?? new
object[0];
IEnumerable<object> sourceAsEnumerable =
sourceValue.Cast<object>();
IPageOf sourceAsPageOf = context.SourceValue as IPageOf;
//
// work out paging content types
//
Type sourceElementType =
context.SourceType.GetGenericArguments()[0];
Type destElementType =
context.DestinationType.GetGenericArguments()[0];
//
// create a temp array with the items
//
var tempArray = new object[sourceAsPageOf.Count];
var emptyArray = new object[] { };
int index = sourceAsPageOf.PageIndex;
int pageSize = sourceAsPageOf.PageSize;
int totalItemCount = sourceAsPageOf.TotalCount;
var destination = (context.DestinationValue ??
Activator.CreateInstance(typeof(StaticPageOf<>).MakeGenericType(destElementType),
new object[]{
emptyArray,index, pageSize, totalItemCount
}));
int i = 0;
foreach (object item in sourceAsEnumerable)
{
var typeMap =
mapper.ConfigurationProvider.FindTypeMapFor(item, sourceElementType,
destElementType);
Type targetSourceType = typeMap != null ?
typeMap.SourceType : sourceElementType;
Type targetDestinationType = typeMap != null ?
typeMap.DestinationType : destElementType;
var newContext = context.CreateElementContext(typeMap,
item, targetSourceType, targetDestinationType, i);
object mappedValue = mapper.Map(newContext);
tempArray[i] = mappedValue;
//SetElementValue(enumerable, mappedValue, i);
i++;
}
//
// add range to the final destination
//
var destinationAsIList = (destination as IList);
foreach (var item in tempArray)
{
destinationAsIList.Add(item);
}
object valueToAssign = destination;
return valueToAssign;
}
}
Works great!
--
You received this message because you are subscribed to the Google Groups "AutoMapper-users" group.
To post to this group, send email to automapp...@googlegroups.com.
To unsubscribe from this group, send email to automapper-use...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/automapper-users?hl=en.
The lack of clarity in my original post was down to my inability to
understand and articulate what I wanted Automapper to do internally.
After I sat down and read EnumerableMapperBase and absorbed it I
understood what was needed from my IPageOf<T> concrete types.
Basically, Automapper at it's core deals with generic list types using
their non-generic friends. What I needed was to create a
WrappingPageOf<T> that accepted a non-generic IEnumerable and cast
during population.
But then I realised as long as the concrete IPageOf<T> supports
implemented IList I could populate without wrapping.
I just needed to wrap my head around the problem and admit deriving
from EnumerableMapperBase wasn't going to help me.
The code in my previous post works great and now PageOf mapping is
something I get for free thanks to Automapper and MVC.
Cheers,
CV
> > automapper-use...@googlegroups.com<automapper-users%2Bunsubscrib e...@googlegroups.com>