title: Using AutoMapper with F#
body: <p>I'm trying to use <a href="https://github.com/AutoMapper/AutoMapper" rel="noreferrer">AutoMapper</a> from F#, but I'm having trouble setting it up due to AutoMapper's heavy use of LINQ Expressions.</p>
  
  <p>Specifically, the AutoMapper type <code>IMappingExpression&lt;'source, 'dest&gt;</code> has a method with this signature:</p>
  
  <pre><code>ForMember(destMember: Expression&lt;Func&lt;'dest, obj&gt;&gt;, memberOpts: Action&lt;IMemberConfigurationExpression&lt;'source&gt;&gt;)
  </code></pre>
  
  <p>This is typically used in C# like this:</p>
  
  <pre class="lang-cs prettyprint-override"><code>Mapper.CreateMap&lt;Post, PostsViewModel.PostSummary&gt;()
      .ForMember(x =&gt; x.Slug, o =&gt; o.MapFrom(m =&gt; SlugConverter.TitleToSlug(m.Title)))
      .ForMember(x =&gt; x.Author, o =&gt; o.Ignore())
      .ForMember(x =&gt; x.PublishedAt, o =&gt; o.MapFrom(m =&gt; m.PublishAt));
  </code></pre>
  
  <p>I made an F# wrapper that arranges things so that type inference can work. This wrapper allows me to translate the C# example above into something like this:</p>
  
  <pre><code>Mapper.CreateMap&lt;Post, Posts.PostSummary&gt;()
  |&gt; mapMember &lt;@ fun x -&gt; x.Slug @&gt; &lt;@ fun m -&gt; SlugConverter.TitleToSlug(m.Title) @&gt;
  |&gt; ignoreMember &lt;@ fun x -&gt; x.Author @&gt;
  |&gt; mapMember &lt;@ fun x -&gt; x.PublishedAt @&gt; &lt;@ fun m -&gt; m.PublishAt @&gt;
  |&gt; ignore
  </code></pre>
  
  <p>This code compiles, and it seems pretty clean as far as syntax and usage. However, at runtime AutoMapper tells me this:</p>
  
  <blockquote>
    <p>AutoMapper.AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.</p>
  </blockquote>
  
  <p>I presume this is caused by the fact that I have to convert <code>Expr&lt;'a -&gt; 'b&gt;</code> into <code>Expression&lt;Func&lt;'a, obj&gt;&gt;</code>. I convert the <code>'b</code> to <code>obj</code> with a cast, which means my lambda expression is no longer simply a property access. I get the same error if I box the property value in the original quotation, and don't do any splicing at all inside <code>forMember</code> (see below). However, if I don't box the property value, I end up with <code>Expression&lt;Func&lt;'a, 'b&gt;&gt;</code> which does not match the parameter type that <code>ForMember</code> expects, <code>Expression&lt;Func&lt;'a, obj&gt;&gt;</code>.</p>
  
  <p>I think that this would work if AutoMapper's <code>ForMember</code> was completely generic, but forcing the return type of the member access expression to be <code>obj</code> means that I can only use it in F# for properties that are already directly of type <code>obj</code> and not a subclass. I can always resort to using the overload of <code>ForMember</code> that takes the member name as a string, but I thought I'd check to see if anyone has a brilliant work-around before I give up on compile-time typo-checking.</p>
  
  <p>I'm using this code (plus the LINQ part of F# PowerPack) to convert an F# quotation into a LINQ expression:</p>
  
  <pre><code>namespace Microsoft.FSharp.Quotations
  
  module Expr =
      open System
      open System.Linq.Expressions
      open Microsoft.FSharp.Linq.QuotationEvaluation
  
      // http://stackoverflow.com/questions/10647198/how-to-convert-expra-b-to-expressionfunca-obj
      let ToFuncExpression (expr:Expr&lt;'a -&gt; 'b&gt;) =
          let call = expr.ToLinqExpression() :?&gt; MethodCallExpression
          let lambda = call.Arguments.[0] :?&gt; LambdaExpression
          Expression.Lambda&lt;Func&lt;'a, 'b&gt;&gt;(lambda.Body, lambda.Parameters) 
  </code></pre>
  
  <p>This is the actual F# wrapper for AutoMapper:</p>
  
  <pre><code>namespace AutoMapper
  
  /// Functions for working with AutoMapper using F# quotations,
  /// in a manner that is compatible with F# type-inference.
  module AutoMap =
      open System
      open Microsoft.FSharp.Quotations
  
      let forMember (destMember: Expr&lt;'dest -&gt; 'mbr&gt;) (memberOpts: IMemberConfigurationExpression&lt;'source&gt; -&gt; unit) (map: IMappingExpression&lt;'source, 'dest&gt;) =
          map.ForMember(Expr.ToFuncExpression &lt;@ fun dest -&gt; ((%destMember) dest) :&gt; obj @&gt;, memberOpts)
  
      let mapMember destMember (sourceMap:Expr&lt;'source -&gt; 'mapped&gt;) =
          forMember destMember (fun o -&gt; o.MapFrom(Expr.ToFuncExpression sourceMap))
  
      let ignoreMember destMember =
          forMember destMember (fun o -&gt; o.Ignore())
  </code></pre>
  
  <h2>Update:</h2>
  
  <p>I was able to use <a href="http://www.fssnip.net/c6" rel="noreferrer">Tomas's sample code</a> to write this function, which produces an expression that AutoMapper is satisfied with for the first argument to <code>IMappingExpression.ForMember</code>.</p>
  
  <pre><code>let toAutoMapperGet (expr:Expr&lt;'a -&gt; 'b&gt;) =
      match expr with
      | Patterns.Lambda(v, body) -&gt;
          // Build LINQ style lambda expression
          let bodyExpr = Expression.Convert(translateSimpleExpr body, typeof&lt;obj&gt;)
          let paramExpr = Expression.Parameter(v.Type, v.Name)
          Expression.Lambda&lt;Func&lt;'a, obj&gt;&gt;(bodyExpr, paramExpr)
      | _ -&gt; failwith "not supported"
  </code></pre>
  
  <p>I still need the PowerPack LINQ support to implement my <code>mapMember</code> function, but they both work now.</p>
  
  <p>If anyone is interested, they can find the <a href="http://www.fssnip.net/c7" rel="noreferrer">full code here</a>.</p>