Extending CopyHelper using Generics

In my last post, I created a method that does the grunt work of copying data from an instance of one class to an instance of another type. I often find myself copying data between the properties of my data layer classes and those of my user interface like this.

// Copy the data from the customer to the view
view.Address = customer.Address;
view.Country = customer.Country;
view.FirstName = customer.FirstName;
view.LastName = customer.LastName;
view.PostalCode = customer.PostalCode;
view.Province = customer.Province;

The newly created CopyHelper class allows me to shorten that to this.

// Copy the data from the customer to the view (using reflection in .NET 1.x)
CopyHelper.Copy( typeof(ICustomer), customer, typeof(ICustomerView), view );

Today, I want to extend that code using Generics and a fluent interface so that I can write code like this.

// Copy the data from the customer to the view (using reflection and generics in .NET 2.0)
Copier<ICustomer>.Copy( customer ).To<ICustomerView>( view );

Internally, I use my CopyHelper class from my last post. I extend that by creating a generic Copier class. I make the constructor private so that it can only be created as a part of the fluent interface, in this case the static copy method. Using the instance of the Copier class that was returned from that method, you can then copy To or From another class instance.

Here is the code.

public sealed class Copier<T1> where T1 : class
{
    #region Private Members

    private readonly T1 _subject;

    #endregion

    #region Public Interface

    /// <summary>
    /// Begin the copying process.
    /// </summary>
    /// <param name="interface1">The object you are copying from or to</param>
    /// <returns>An instance of the Copier class so that you can 
    /// continue with the copy to/from in a fluent interface.</returns>
    public static Copier<T1> Copy( T1 interface1 )
    {
        return new Copier<T1>( interface1 );
    }

    #endregion

    #region Construction

    /// <summary>
    /// Private constructor so that it can only be created as a part of a fluent interface.
    /// </summary>
    /// <param name="subject"></param>
    private Copier( T1 subject )
    {
        _subject = subject;
    }

    #endregion

    #region Copier Methods

    /// <summary>
    /// Copies properties from the subject to the passed in object.
    /// </summary>
    /// <typeparam name="T2">The type of object you are copying into.</typeparam>
    /// <param name="to">The object to copy into.</param>
    /// <returns>The modified object that you passed in.</returns>
    public T2 To<T2>( T2 to ) where T2 : class
    {
        CopyHelper.Copy( typeof( T1 ), _subject, typeof( T2 ), to );
        return to;
    }

    /// <summary>
    /// Copies properties from the passed in object into the subject.
    /// </summary>
    /// <typeparam name="T2">The type of object you are copying from.</typeparam>
    /// <param name="from">The object to copy from.</param>
    /// <returns>The modified subject that you originally passed in the Copy method.</returns>
    public T1 From<T2>( T2 from ) where T2 : class
    {
        CopyHelper.Copy( typeof( T2 ), from, typeof( T1 ), _subject );
        return _subject;
    }

    #endregion
}

I would like to constrain T1 and T2 to interfaces at compile time, but I am not sure if that can be done. If you have ideas, please post them in the comments. I thought of using reflection to check if T1 and T2 are interfaces at run time, but I am a big believer in favouring compile time errors over run time errors.

In my next post, I am going to use C# 3.0 extension methods to further simplify copying allowing you to write code like this.

// Copy the data from the customer to the view (using extension methods in C# 3.0)  
customer.CopyTo<ICustomerView>( view );

I am very interested in hearing your feedback on this, so be sure to post to the comments. Do you think this is a good idea? Do you have suggestions for improvements? Let me know.

4 thoughts on “Extending CopyHelper using Generics

  1. Jarrett,

    That is very similar to where I am going in the next post except that I also use generics so that you can copy from one type to another.

  2. I use an extension method to copy fields that have a public getter and setter.
    public static void CopyFrom(this T to, T from)
    {
    foreach (PropertyInfo field in typeof(T).GetProperties())
    {
    if (field.CanWrite) field.SetValue(to, field.GetValue(from, null), null);
    }
    }

Comments are closed.