Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper mapping with generic extension methods

I want to map my objects with generic extension methods.

public class Customer    
{    
    public string FirstName { get; set; }    
    public string LastName { get; set; }    
    public string Email { get; set; }    
    public Address HomeAddress { get; set; }    
    public string GetFullName()    
    {  
        return string.Format(“{0} {1}”, FirstName, LastName);
    }    
}

And this is viewmodel

public class CustomerListViewModel    
{    
    public string FullName { get; set; }
    public string Email { get; set; }    
    public string HomeAddressCountry { get; set; }    
}

So I am creating map, Mapper.CreateMap<Customer, CustomerListViewModel>();

And I want to create an extension method

public static class MapperHelper
{
    public static CustomerListViewModel ToViewModel(this Customer cust)
    {
        return AutoMapper.Mapper.Map<Customer, CustomerListViewModel>(cust);
    }
}

But I want to make generic this helper:

public static class MapperHelper<TSource, TDest>
{
    public static TDest ToViewModel(this TSource cust)
    {
        return AutoMapper.Mapper.Map<TSource, TDest>(cust);
    }
}

Gives error: Extension method can only be declared in non-generic, non-nested static class

If I can not make generic, I should create helper class for all mapping. Is there any way to solution?

like image 817
barteloma Avatar asked Apr 22 '15 09:04

barteloma


People also ask

How do I create a new expression in automapper?

CreateMapExpression in AutoMapper creates an expression for mapping between Source to Destination. In the next line we use the mapper expression and pass this to Compose extension method to build a new expression. And finally we call Where method on Users DBSet and it returns IQueriable of type Destination.

How to configure enum mapper in automapper?

The built-in enum mapper is not configurable, it can only be replaced. Alternatively, AutoMapper supports convention based mapping of enum values in a separate package AutoMapper.Extensions.EnumMapping. For method CreateMap this library provide a ConvertUsingEnumMapping method.

Is it possible to implement find method in automapper?

Now, the real issue is when we want to implement Find method which accepts Expression<Func<Source, bool. Mapping an expression of func of type source to expression of func of type destination is more difficult as Jimmy Bogard main author of Automapper stated in this mailing list.

How do I use automapper OData mapping?

AutoMapper extentions for mapping expressions (OData) To use, configure using the configuration helper method: var mapper = new Mapper (new MapperConfiguration (cfg => { cfg. AddExpressionMapping (); // Rest of your configuration })); // or if using the MS Ext DI: services.


3 Answers

Even better than these solutions is to use the non-generic Map method:

public static class MapperHelper
{
    public static TDest MapTo<TDest>(this object src)
    {
        return (TDest)AutoMapper.Mapper.Map(src, src.GetType(), typeof(TDest));
    }
}

In your code:

var model = customter.MapTo<CustomerViewModel>();

Now you don't need the superfluous Source type in your generic method.

like image 178
Jimmy Bogard Avatar answered Oct 19 '22 15:10

Jimmy Bogard


Can't you just do this?:

public static class MapperHelper
{
    public static TDest ToViewModel<TSource, TDest>(this TSource cust)
    {
       return AutoMapper.Mapper.Map<TSource, TDest>(cust);
    }
}
like image 43
Arion Avatar answered Oct 19 '22 15:10

Arion


You can't define extension methods in a generic class because there would be no way for you to specify the type parameters when you invoke it!

public static class MapperHelper<TSource, TTarget>
{
  public static TTarget ToViewModel(this TSource source)
  {
    ...
  }
}

...

// this is no problem if we invoke our method like a
// static method:-
var viewModel = MapperHelper<MyModel, MyViewModel>.ToViewModel(model);

// but if we use the extension method syntax then how
// does the compiler know what TSource and TTarget are?:-
var viewModel = model.ToViewModel();

You have to make the method generic instead:-

public static class MapperHelper
{
  public static TTarget ToViewModel<TSource, TTarget>(this TSource source)
  {
    ...
  }
}

...

var viewModel = model.ToViewModel<MyModel, MyViewModel>();
like image 1
Iain Galloway Avatar answered Oct 19 '22 14:10

Iain Galloway