Mapping items from one class to another if Items a

2019-02-20 03:21发布

问题:

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.

回答1:

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:

  1. From Tools menu click on NuGet Package Manager ==> Package Manager Console
  2. Then type the following command:

    PM> Install-Package AutoMapper
    


回答2:

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);


回答3:

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);


回答4:

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.