I have created a ListTypeConverter:
type ListTypeConverter<'source, 'destination>() =
interface ITypeConverter<'source list, Proxies.List> with
member this.Convert(source, destination, context) =
let proxyList = new Proxies.List()
source
|> List.map(fun item -> _mapper.Map<'source, 'destination>(item))
|> List.iter(fun item -> proxyList.addEnd(item) |> ignore)
proxyList
And usage: ForMemberFs by Ian Griffiths
this.CreateMap<SourceItemType list, Proxies.List>().ConvertUsing<ListTypeConverter<SourceItemType, DestItemType>>()
this.CreateMap<SourceType, DestType>().
ForMemberFs((fun d -> d.MyNonGenericList), (fun opts -> opts.MapFrom(fun s -> s.MyGenericList))).
This works fine if I only have one property on my primary map that maps from a 'a list -> Proxy.List
. But the moment I introduce a second mapping from a 'b -> Proxy.List
then I get an InvalidCastException.
Introducing a second mapping causes the exception:
this.CreateMap<SourceItemType list, Proxies.List>().ConvertUsing<ListTypeConverter<SourceItemType, DestItemType>>()
this.CreateMap<SourceItemType2 list, Proxies.List>().ConvertUsing<ListTypeConverter<SourceItemType2, DestItemType2>>()
this.CreateMap<SourceType, DestType>().
ForMemberFs((fun d -> d.MyNonGenericList), (fun opts -> opts.MapFrom(fun s -> s.MyGenericList))).
ForMemberFs((fun d -> d.MyNonGenericList2), (fun opts -> opts.MapFrom(fun s -> s.MyGenericList2))).
Exception:
Unable to cast object of type 'obj' to type 'DestItemType'
So, my problem is a bit deeper than just F# and AutoMapper. The Proxies.List type is actually gotten via a TypeProvider for Microsoft Dynamics AX that we've written in-house. I wanted to exclude that variable from the equation, so I wrote a simple script using System.Collections.Generic.List<'t> -> System.Collections.ArrayList
(which is non-generic) and I was able to successfully cast from items in my ArrayList
back to their correct "destination" type.
While I'm here, we came up with some pretty cool F# helpers for AutoMapper:
type OptionExpressions =
static member MapFrom<'source, 'destination, 'sourceMember, 'destinationMember> (e: 'source -> 'sourceMember) =
System.Action<IMemberConfigurationExpression<'source, 'destination, 'destinationMember>> (fun (opts: IMemberConfigurationExpression<'source, 'destination, 'destinationMember>) -> opts.MapFrom(e))
static member UseValue<'source, 'destination, 'value> (e: 'value) =
System.Action<IMemberConfigurationExpression<'source, 'destination, 'value>> (fun (opts: IMemberConfigurationExpression<'source, 'destination, 'value>) -> opts.UseValue(e))
static member Ignore<'source, 'destination, 'destinationMember> () =
System.Action<IMemberConfigurationExpression<'source, 'destination, 'destinationMember>> (fun (opts: IMemberConfigurationExpression<'source, 'destination, 'destinationMember>) -> opts.Ignore())
Usage:
// Shortened local helpers
let mapFrom = OptionExpressions.MapFrom
let ignoreMap = OptionExpressions.Ignore
let useValue = OptionExpressions.UseValue
this.CreateMap<Source, Destination>()
.ForMemberFs((fun d -> d.DestMember1), mapFrom (fun s -> s.SourceMember1))
.ForMemberFs((fun d -> d.DestMember2), useValue (MyValue))
.ForMemberFs((fun d -> d.DestMember3), ignoreMap ())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With