2

With the exception of 3rd party mapper applications like Automapper, what is the best way to copy data from one object to another object that have limited properties (not exactly a clone task).

Customer
{
   string Name { get; set; }
   string SSN { get; set; }
   object Addresses { get; set; }
}

to 

CustomerData
{
   string Name { get; set; }
   object Addresses { get; set; }
}

For example, I want to copy Customer to CustomerData (Addressses object might be a nested object, and object may have more properties). This, of course, is shortened for demo purposes. There are a lot more fields in Customer that I don't want copied to CustomerData.

Rod
  • 14,529
  • 31
  • 118
  • 230
  • 2
    Define "best". Fastest? Least code? Most flexible? You can obviously just copy properties explicitly but I assume you want something different. – D Stanley May 23 '16 at 18:31
  • Least code, fastest respectively – Rod May 23 '16 at 18:33
  • 2
    I think you're looking for a special cast operator or even a generic extension that does this for you. Have a look at one of the answers to [this](http://stackoverflow.com/questions/3672742/cast-class-into-another-class-or-convert-class-to-another) question. – Dominic B. May 23 '16 at 18:33
  • 1
    @Rod those are probably conflicting goals. The "least code" would be to use reflection to line up properties by name and have some mechanism to add exceptions (similar to what AutoMapper does). The "fastest" would be to just copy each parameter explicitly in code. There's nothing magical in the framework that does either for you. – D Stanley May 23 '16 at 18:46
  • Got it, that makes sense now. – Rod May 23 '16 at 18:53
  • @DStanley they aren't necessarily conflicting goals. There is a lot you can do with reflection and caching delegates that can make it very fast. It is also highly flexible, but unfortunately at the cost of some daunting complexity for those not familiar with the pattern. – DVK May 23 '16 at 19:23
  • @Rod is your question specific to customer and CustomerData entities or it is general as to how you control what to copy or not? I believe your question is being answered here by elite members assuming it's a specific case but my understanding is its not what you meant. Because I answered it as if in general what kind of approach one might follow – Mukesh Adhvaryu May 24 '16 at 05:21
  • It was more of a general approach question about ways to copy data from one object A with many properties to an object B with a subset of properties of object A. With the exception of using 3rd party programs like auto mapper. – Rod May 24 '16 at 05:28
  • @Rod thanks for clarification. I was confused to see usage of explicit cast in some answers. But I don't consider operator overloading especially casting is a general practice. In-fact it is very special feature needs to be used wisely. I believe it should not be accepted as generic solution. – Mukesh Adhvaryu May 24 '16 at 07:24

3 Answers3

1

Having a ToOtherType method is pretty short customer.ToCustomerData() and should be fast (compared to something weird like reflection).

//ToOtherType method
public CustomerData ToCustomerData(){
    var customerData = new CustomerData();
    customerData.Name = Name;
    customerData.Addresses = Addresses;
    return customerData;
}

Using explicit or implicit operators lets you write even shorter code: CustomerData cd = customer (implicit) or CustomerData cd = (CustomerData)customer (explicit). Be careful around implicit operators though, they can create interesting debugging headaches.

//explicit operator
public static explicit operator CustomerData(Customer c){
    var customerData = new CustomerData();
    customerData.Name = c.Name;
    customerData.Addresses = c.Addresses;
    return customerData;
}

I'd go with the ToOtherType pattern, it's a bit more obvious what's going on, especially if you have anyone else working on the code who won't recognize it. Also, the operator pattern won't work in some situations (sealed objects, etc.).

Online example: https://dotnetfiddle.net/56p0Lh

Chakrava
  • 823
  • 7
  • 10
  • 1
    Seconding the static explicit operator. It keeps the code concise but doesn't obfuscate what is going on too much. It also has the benefit of keeping your mapping code in one place so when you modify your mapped objects you don't have to crawl all over the codebase looking for things to update. – DVK May 23 '16 at 19:18
0

Which properties to copy and which to ignore is highly subjective. It has to be a customized task. If I were to do this, in a case you described, I would do the following:

public interface ICustomCloning{
    void CopyFrom(ICustomCloning other);
}

class Customer: ICustomCloning 
{
    string Name { get; set; }
    string SSN { get; set; }
    object Addresses { get; set; }

    public virtual void CopyFrom(ICustomCloning other){
       if(other is Customer)
       {
           var o = other as Customer;
           //copy values from o. 
           //this.Name = o.Name;
       }
       //else if(other is Addresses)
       //this.Addresses.CopyFrom(other);
    }
}
class CustomerData: ICustomCloning 
{
    string Name { get; set; }
    object Addresses { get; set; }

    public virtual void CopyFrom(ICustomCloning other){
       if(other is CustomerDa)
       {
           var o = other as CustomerData;
           //copy values from o. 
           //this.Name = o.Name;
       }
       //else if(other is Addresses)
       //this.Addresses.CopyFrom(other);
    }
}
public class Addresses: ICustomCloning{
    public virtual void CopyFrom(ICustomCloning other){
        if(other is Addresses){
            var o as Addresses;
            //Do your copy from o.
        }
        else if(other is Customer)
        //var o = (other as Customer). Addresses;
        //Do your copy from o
    }
}
Mukesh Adhvaryu
  • 642
  • 5
  • 16
-1

@Chakrava had the right answer with the static explicit operator as these allow you to treat conversions like a built-in cast (eg. CustomerData data = (CustomerData)myCustomer;). If you don't like the idea of doing that, some other options would be (aside from writing a ToSomeType() method):

Constructor Overloads

public CustomerData
{
    public CustomerData(ICustomer customer)
    {
        // put your mapping code here
    }
}

var data = new CustomerData(myCustomer);

Extension Methods

Similar to a ToSomeType() method...

public static CustomerData ToCustomerData(this Customer customer)
{
    // mapping code here

    return myCustomerData;
}

Inheritance

CustomerData
{
   string Name { get; set; }
   object Addresses { get; set; }
}

Customer : CustomerData
{
   string SSN { get; set; }
}

Reflection

Probably best to use auto-mapper or similar. Lots of examples of using reflection out there, so I won't go into it.

Object Initializer Syntax

Don't discount this as either a one-off (think YAGNI) or to supplement some of the other mechanisms described herein. Don't litter your code with it though.

var data = new CustomerData(){ Name = myCustomer.Name, Addresses = myCustomer.Addresses};
DVK
  • 2,726
  • 1
  • 17
  • 20