Say I have one class
that looks like this:
public class Person
{
public string Name {get; set;}
public int Number {get; set;}
}
And another that looks like this:
public class Dog
{
public string Name {get; set;}
public int Number {get; set;}
}
They are two different classes, but they happen to have the exact same elements (a string called Name
and an int called Number
)
Is there an easy way in C# to, say, if I had an instance of Person
to then create an instance of Dog
with the same Name
and Number
?
For example if I had:
Person person = new Person();
person.Name = "George";
person.Number = 1;
I know I can't simply go:
Dog dog = person;
Because they are two different types. But is there a way in C# to check "oh, if they have the same element, set the same elements of Dog
to equal that of Person
.
But I feel there has to be an easier way than doing something like:
dog.Name = person.Name;
dog.Number = person.Number;
Especially if the class has a LOT of elements. Also if anyone is wondering, these two different classes are in two different pieces of the API, so I can't simply make them related either.
You can use AutoMapper:
public Dog UsingAMR(Person prs)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Person, Dog>();
});
IMapper mapper = config.CreateMapper();
return mapper.Map<Person, Dog>(prs);
}
Then you can easily:
Person ps = new Person {Name = "John", Number = 25};
Dog dog = UsingAMR(ps);
Just don't forget to install AutoMapper
first from the package manager console as mentioned in the reference:
- From Tools menu click on NuGet Package Manager ==> Package Manager Console
Then type the following command:
PM> Install-Package AutoMapper
An object oriented approach.
public class Mammal
{
public Mammal(Mammal toCopy)
{
Name = toCopy.Name;
Number = toCopy.Number;
}
public string Name {get; set;}
public int Number {get; set;}
}
public class Person: Mammal
{
public Person(Mammal toCopy) {} /* will default to base constructor */
}
public class Dog: Mammal
{
public Dog(Mammal toCopy) {} /* will default to base constructor */
}
This will allow the following:
Person person = new Person();
person.Name = "George";
person.Number = 1;
Dog dog = new Dog(person);
Install AutoMapper
package in your project.
As a best practice (for web applications) you can create new class (should derives from Profile
) in your App_Start
folder, that will contain all your mappings for your project.
namespace MyApp.App_Start
{
public class MyAppMapping : Profile
{
public MyAppMapping()
{
CreateMap<Person, Dog>();
//You can also create a reverse mapping
CreateMap<Dog, Person>();
/*You can also map claculated value for your destination.
Example: you want to append "d-" before the value that will be
mapped to Name property of the dog*/
CreateMap<Person, Dog>()
.ForMember(d => d.Days,
conf => conf.ResolveUsing(AppendDogName));
}
private static object AppendDogName(Person person)
{
return "d-" + person.Name;
}
}
}
Then Initialize your mapping inside the Application_Start
method in Global.asax
protected void Application_Start()
{
Mapper.Initialize(m => m.AddProfile<MyAppMapping>());
}
You can now use the mappings that you have created
var dog = AutoMapper.Mapper.Map<Person, Dog>(person);
If you don't work with big generic list, you can do it using LinQ.
var persons = new List<Person>();
// populate data [...]
var dogs = persons.Select(p=>new Dog{Name=p.Name,Number=p.Number}).ToList();
It's easy to remember, and you can filter data previously.