Examples

Every example below is executed and asserted against the real library before publishing — none of these are hypothetical.

1. Basic mapping

Same-named, same-type properties are mapped automatically — no configuration beyond CreateMap.

public class SimpleSource
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

public class SimpleDestination
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

var config = new MapperConfig();
config.CreateMap<SimpleSource, SimpleDestination>();
IMapper mapper = new Mapper(config);

var result = mapper.Map<SimpleDestination>(new SimpleSource { Id = 1, Name = "Ada" });

// result.Id == 1
// result.Name == "Ada"

2. Custom member mapping with ForMember

Use ForMember to compute or transform a single top-level property.

var config = new MapperConfig();
config.CreateMap<SimpleSource, SimpleDestination>()
    .ForMember(dest => dest.Name, src => src.Name.ToUpperInvariant());
IMapper mapper = new Mapper(config);

var result = mapper.Map<SimpleDestination>(new SimpleSource { Id = 1, Name = "Ada" });

// result.Name == "ADA"

3. Nested object mapping

When a destination property's type differs from the source property it corresponds to, ForMember's function must produce the already-mapped value itself — it does not happen implicitly. The usual pattern is to close over a Mapper built from the same config and call back into it:

public class Country { public string Name { get; set; } = ""; }
public class CountryViewModel { public string Name { get; set; } = ""; }
public class Organization
{
    public string OrgName { get; set; } = "";
    public Country Country { get; set; } = new();
}
public class OrganizationViewModel
{
    public string OrgName { get; set; } = "";
    public CountryViewModel CountryViewModel { get; set; } = new();
}

var config = new MapperConfig();
config.CreateMap<Country, CountryViewModel>();

var mapper = new Mapper(config);

config.CreateMap<Organization, OrganizationViewModel>()
    .ForMember(dest => dest.CountryViewModel,
               src => mapper.Map<CountryViewModel>(src.Country));

var result = mapper.Map<OrganizationViewModel>(new Organization
{
    OrgName = "Acme",
    Country = new Country { Name = "Wonderland" }
});

// result.OrgName == "Acme"
// result.CountryViewModel.Name == "Wonderland"
Why this matters: passing the raw src.Country straight through (without the mapper.Map<CountryViewModel>(...) call) throws InvalidOperationException at runtime, since a Country instance cannot be assigned to a CountryViewModel property. This exact mistake was previously in this project's own README — it's called out here so it doesn't happen to you.

4. Deep nested paths with ForPath

ForPath targets a property several levels deep. Multiple ForPath calls under the same top-level destination property are all applied to the same nested instance.

public class Location
{
    public string Address { get; set; } = "";
    public Organization Organization { get; set; } = new();
}
public class LocationViewModel
{
    public string Address { get; set; } = "";
    public OrganizationViewModel OrganizationViewModel { get; set; } = new();
}

var config = new MapperConfig();
config.CreateMap<Location, LocationViewModel>()
    .ForPath(dest => dest.OrganizationViewModel.CountryViewModel.Name,
             src => src.Organization.Country.Name)
    .ForPath(dest => dest.OrganizationViewModel.OrgName,
             src => src.Organization.OrgName);

var mapper = new Mapper(config);

var result = mapper.Map<LocationViewModel>(new Location
{
    Address = "1 Main St",
    Organization = new Organization
    {
        OrgName = "Acme",
        Country = new Country { Name = "Wonderland" }
    }
});

// result.Address == "1 Main St"
// result.OrganizationViewModel.OrgName == "Acme"
// result.OrganizationViewModel.CountryViewModel.Name == "Wonderland"

5. Collection mapping

Map a List<TSource> directly to a List<TDestination> — each element is mapped individually.

var config = new MapperConfig();
config.CreateMap<SimpleSource, SimpleDestination>();
IMapper mapper = new Mapper(config);

var sources = new List<SimpleSource>
{
    new() { Id = 1, Name = "Ada" },
    new() { Id = 2, Name = "Alan" },
};

var result = mapper.Map<List<SimpleDestination>>(sources);

// result.Count == 2
// result[0].Name == "Ada"
// result[1].Name == "Alan"

6. Nested collection properties

A List<T> destination property (not just the top-level Map<List<T>> call) is also auto-mapped, as long as a map is registered for the item types.

public class Employee { public string Name { get; set; } = ""; }
public class EmployeeViewModel { public string Name { get; set; } = ""; }

public class Department
{
    public string DeptName { get; set; } = "";
    public List<Employee> Employees { get; set; } = new();
}
public class DepartmentViewModel
{
    public string DeptName { get; set; } = "";
    public List<EmployeeViewModel> Employees { get; set; } = new();
}

var config = new MapperConfig();
config.CreateMap<Employee, EmployeeViewModel>();
config.CreateMap<Department, DepartmentViewModel>();
IMapper mapper = new Mapper(config);

var result = mapper.Map<DepartmentViewModel>(new Department
{
    DeptName = "Engineering",
    Employees = new List<Employee>
    {
        new() { Name = "Ada" },
        new() { Name = "Alan" },
    }
});

// result.DeptName == "Engineering"
// result.Employees.Count == 2
// result.Employees[0].Name == "Ada"
Also works for array destinations: declaring EmployeeViewModel[] Employees instead of List<EmployeeViewModel> Employees on DepartmentViewModel maps the same way — the source property still needs to be a List<T>, but the destination property can be a List<T>, any of IList<T>/ICollection<T>/IReadOnlyList<T>/IReadOnlyCollection<T>/IEnumerable<T>, or an array.