tags:

views:

378

answers:

8

I've been working with C# for many years now, but just come across this issue that's stumping me, and I really don't even know how to ask the question, so, to the example!

public interface IAddress
{
  string Address1 { get; set; }
  string Address2 { get; set; }
  string City { get; set; }
  ...
}

public class Home : IAddress
{
  // IAddress members
}

public class Work : IAddress
{
  // IAddress members
}

My question is, I want to copy the value of the IAddress properties from one class to another. Is this possible in a simple one-line statement or do I still have to do a property-to-property assignment of each one? I'm actually quite surprised that this seemingly simple thing has stumped me like it has... If it's not possible in a concise way, does anyone have any shortcuts they use to do this sort of thing?

Thanks!

+2  A: 

There's no one-liner for this.

If you do it a lot, you could look into some form of code generation, perhaps using T4 templates and Reflection.

BTW COBOL has a statement for this: MOVE CORRESPONDING HOME TO WORK.

John Saunders
+10  A: 

You could build an extension method:

public static void CopyAddress(this IAddress source, IAddress destination)
{
    if (source is null) throw new ArgumentNullException("source");
    if (destination is null) throw new ArgumentNullException("destination");

    //copy members:
    destination.Address1 = source.Address1;
    //...
}
Joel Coehoorn
I really like this solution. Thanks!
opedog
See the response below that has a generic extension method that isn't fragile when the interface changes or set/get methods are added/removed.
plinth
A: 

You would need to create a method to do this

public void CopyFrom(IAddress source)
{
    this.Address1 = source.Address1;
    this.Address2 = source.Address2;
    this.City = source.city;
}
Mitchel Sellers
This is a fragile method, likely to break if new properties are added.
plinth
Yes, most ways, except if you use reflection. Doing what the user is talking about this is a valid option.
Mitchel Sellers
A: 

You could have a constructor on each class taking an IAddress and have implemented members populated within.

eg

public WorkAddress(Iaddress address)
{
    Line1 = IAddress.Line1;
    ...
}

For maintainability use reflection to get property names.

HTH,

Dan

Daniel Elliott
A: 

If you encapsulate the common parts of the home and work address into a separate class it may make your life easier. Then you can simply copy across that property. This seems like better design to me.

Alternatively, you may be able to hack together a solution with reflection and attributes where the value of the properties in one object are copied over to the matching (and marked) properties in the other. Of course this is not going to be a one-line solution either but it may be faster and more maintainable than others if you have a large set of properties.

Robert Venables
+1  A: 

I don't believe there's a language ready solution for this (all the properties would need to have getters and setters).

You could create Address as an abstract class, with a Copy(Address add) method.

Alternatively, you could make Home and Work to HAVE an IAddress, and not extend one. The copy would then be immediate.

Samuel Carrijo
+1  A: 

Jimmy Bogard's AutoMapper is very useful for that kind of mapping operation.

Martinho Fernandes
Apache Commons had a library called "BeanUtils" that I used to use when I developed in Java. What Martinho Fernandes suggests appears to be the closest corresponding .net library.
Bryce Fischer
+2  A: 

Here's one way to do it that has nothing to do with interfaces:

public static class ExtensionMethods
{
    public static void CopyPropertiesTo<T>(this T source, T dest)
    {
        var plist = from prop in typeof(T).GetProperties() where prop.CanRead && prop.CanWrite select prop;

        foreach (PropertyInfo prop in plist)
        {
            prop.SetValue(dest, prop.GetValue(source, null), null);
        }
    }
}

class Foo
{
    public int Age { get; set; }
    public float Weight { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return string.Format("Name {0}, Age {1}, Weight {2}", Name, Age, Weight);
    }
}

static void Main(string[] args)
{
     Foo a = new Foo();
     a.Age = 10;
     a.Weight = 20.3f;
     a.Name = "Ralph";
     Foo b = new Foo();
     a.CopyPropertiesTo<Foo>(b);
     Console.WriteLine(b);
 }

In your case, if you only want one set of interface properties to copy you can do this:

((IAddress)home).CopyTo<IAddress>(b);
plinth
You should probably stick a constraint on there - where T : IAddress. Then you could also cache the Reflection lookup rather than doing it for every call and still avoid needing to update the method if the interface changes.
Joel Coehoorn
BTW, I get that you're trying for the more general case, but in this case it seems like trying to use a sledge hammer to hit a nail.
Joel Coehoorn
Your code will break at runtime if `source` and `dest` are different types, which they are in the original question. You can fix it by getting the property list from `T` rather than from `source`. For example: `var plist = from prop in typeof(T).GetProperties() where prop.CanRead `
LukeH
@Joel - you don't need the constraint unless you want to write a version specific to IAddress. The specialization at use time takes care of that for you. It looks like it's a sledge hammer to hit a nail, but that overshadows the robustness of the code in the face of changing interfaces - I have lost enough time tracking down bugs from that class of error that if I have reflection, I prefer it to eliminate that class of bug inherently.
plinth