Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert a custom complex type to another custom complex type

So I have two custom complex types like this (oversimplified for this example):

public class PendingProduct
{
    public string Name { get; set; }
    public string Description { get; set; }
    public int ColorCount { get; set; }
}

Let's say I need this object to know how to convert itself to another type:

public class Product
{
    public string Name { get; set; }
    public string Description { get; set; }
    public ProductColors Colors { get; set;}
}

So when I call a method to convert PendingProduct to Product, I'll execute some custom logic that adds "ColorCount" number of ProductColor objects to the Product class. This is totally oversimplified, but the architecture of the class is really irrelevant here.

What my main question is, is this:

What's the best practice method to use to implement the conversion of one complex type to another complex type when the properties of the objects differ?

In the real world, the properties are very different and I will be writing some custom logic to map what I need from Object A to Object B.

Obviously I could just write a function which takes an input parameter of Object A and returns Object B, but I'm looking for a more "Best Practice" method. Does IConvertible come into play here? Is there something more OOP-like that I can take advantage of rather than just writing a function to do what I want?

Object A should always know how to convert itself to Object B.

EDIT: As a side note, in the real world, Object A and Object B are both Entity Framework 4 entities. I want to take a "Pending Product", convert it to a new Product entity, attach it to the data context and save.

like image 695
Scott Avatar asked Jan 14 '11 19:01

Scott


1 Answers

There are numerous ways this can be done, but they really boil down to either writing the mapping code yourself, handling it through reflection, or relying on a pre-built framework like AutoMapper. I've answered a similar question in another SO question here.

I'll add it here for your reference:

Realistically you could

1.Reflection

public void Map<TSource, TDestination>(TSource source, TDestination destination)
{
  var props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
  var type = typeof(TDestination);

  foreach (var prop in props)
  {
    object value = prop.GetValue(source, null);

    var prop2 = type.GetProperty(prop.Name);
    if (prop2 == null)
      continue;

    if (prop.PropertyType != prop2.PropertyType)
      continue;

    prop2.SetValue(destination, value, null);
  }
}

2.Copy Constructor

public Employee(Person person)
{
  // Copy properties
}

3.Implicit/Explicit Conversion

public static implicit operator Employee(Person person)
{
  // Build instance and return
}

4.AutoMapper

Mapper.Map<Person, Employee>(person);

5.Combination of 3/4:

public static implicit operator Employee(Person person)
{
  return Mapper.Map<Person, Employee>(person);
}

A note on implicit/explicit conversion operators: I believe in using these you won't be generating CLS-compliant code.

AutoMapper does allow you to customise how different properties on the target type are mapped over, e.g.:

Mapper.CreateMap<Person, Employee>()
      .ForMember(e => e.Forename, o => o.MapFrom(p => p.Forename.ToLower()));
like image 76
Matthew Abbott Avatar answered Nov 15 '22 20:11

Matthew Abbott