How do I create a generic mapper for my IPageOf<T>?

402 views
Skip to first unread message

CVertex

unread,
Mar 11, 2010, 6:45:19 AM3/11/10
to AutoMapper-users
I have an interface that defines a page of things with implementations
PageOf<T> and StaticPageOf<T>.

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

CVertex

unread,
Mar 11, 2010, 10:31:22 PM3/11/10
to AutoMapper-users
Howdy,

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!

Jimmy Bogard

unread,
Mar 12, 2010, 8:27:46 AM3/12/10
to automapp...@googlegroups.com
Do a little bit bigger example of what you're trying to do?  Not sure what you mean that AutoMapper doesn't know how to instantiate things without generics.  What are the source/destination types you'd like to have built?

Thanks,

Jimmy


--
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.


CVertex

unread,
Mar 13, 2010, 2:27:10 AM3/13/10
to AutoMapper-users
Hi Jimmy,

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>

Reply all
Reply to author
Forward
0 new messages