views:

2114

answers:

8

Suppose I have two classes with the same interface:

interface ISomeInterface 
{
    int foo{get; set;}
    int bar{get; set;}
}

class SomeClass : ISomeInterface {}

class SomeOtherClass : ISomeInterface {}

Suppose I have an instance of ISomeInterface that represents a SomeClass. Is there an easy way to copy that into a new instance of SomeOtherClass without copying each member by hand?

UPDATE: For the record, I'm not trying to cast the instance of SomeClass into the instance of SomeOtherClass. What I'd like to do is something like this:

ISomeInterface sc = new SomeClass() as ISomeInterface;
SomeOtherClass soc = new SomeOtherClass();

soc.foo = sc.foo;
soc.bar = soc.bar;

I just don't want to have to do that for each by hand as these objects have lots of properties.

+3  A: 

Reflection ... loop through every property, and set it on the corresponding property on the other object.

Joel Martinez
Would you be able to give me an example of how I can do that (or at least point me towards the right methods to be using)? I don't seem to be able to find them on MSDN. :-/
Jason Baker
And this won't work if the propertys are of different types... TYour code will have to compare property types as well as their names... And then you also have the issue of dealing with reference type proprtys - (Deep copy or shallow copy)?
Charles Bretana
+1  A: 

No, to transparently convert (cast) an object from one type to another, the underlying concrete class of the object you have, must inherit from the class the you are trying to cast it to, even if they both inplement the same interface.

Think about it, all two objects have to have in common to implement the same interface is the same subset of method signatures. They might not (probably do not) even have the same properties or data fields.

Charles Bretana
Maybe I misworded myself. I would actually prefer not to cast it. It would be fine by me to copy values from one instance to another. I just don't want to have to write those by hand (the objects have a lot of properties).
Jason Baker
What do you mean, "I just don't want to have to write those by hand"? You could write a reflection tool that examines all fields in one class and looks 4 dupes in the other, and then where there's a match, copy the value... But it would have to compare data types and field names.... messy!
Charles Bretana
Otherwise you will have to code this by hand, field by field or property by property...
Charles Bretana
Hmmm.... I'll take this to mean "there is no easy way to do this." :-/
Jason Baker
If there are really a lot of properties then write a little tool that examines the object using reflection and spits out the code you need for a copy constructor.
Winston Smith
+5  A: 

Isn't the point of an interface to not have to do that? Are you doing something with the concrete implementation of SomeOtherClass? Instead of using the concrete implementation, use the interface and it shouldn't matter if you use SomeClass or SomeOther class.

Other than that, the best you could do is to write some sort of a helper function (you'd still have to do it manually, or look into reflection) that copies each Property on the Interface that would look like this:

public ISomeInterface CopyValues(ISomeInterface fromSomeClass, ISomeInterface toSomeOtherClass) {
//copy properties here
return toSomeOtherClass;
}

However, my first instinct would be to say stay away from the implementation and concentrate using your interface instead, then it won't matter what's lying underneath.

mendicant
+2  A: 

wouldn't this work?

class MyClass : ICloneable
{
public MyClass()
{

}
public object Clone() // ICloneable implementation
{
MyClass mc = this.MemberwiseClone() as MyClass;

return mc;
}

You only have to call: MyClass.Clone().

netadictos
I thought about that, but the only problem is that the base class that both inherits from has their own implementation of Clone that returns an object of the same type. :-/
Jason Baker
+1  A: 

You can create implicit operators in each class to do the conversion for you:

public class SomeClass
{
    public static implicit operator SomeOtherClass(SomeClass sc)
    {
        //replace with whatever conversion logic is necessary
        return new SomeOtherClass()
        {
            foo = sc.foo,
            bar = sc.bar
        }
    }

    public static implicit operator SomeClass(SomeOtherClass soc)
    {
        return new SomeClass()
        {
            foo = soc.foo,
            bar = soc.bar
        }
    }
    //rest of class here
}

and then SomeOtherClass soc = sc; and vice versa would work.

Adam Lassek
+1  A: 

"Would you be able to give me an example of how I can do that (or at least point me towards the right methods to be using)? I don't seem to be able to find them on MSDN" – Jason Baker

Jason, something like the following:

var props = typeof(Foo)
            .GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach (PropertyInfo p in props)
{
     // p.Name gives name of property
}

I'd suggest writing a tool to spit out the code you need for a copy constructor, as opposed to doing it reflectively at runtime - which would be less performant.

Winston Smith
But before you pre-optimize, try it with using on-the-fly reflection. If you're doing something like a standard line-of-business app, a little reflection on properties probably isn't a big deal, and the flexibility of having self-correcting code when props are added or names changed is nice.
Chris Farmer
yes, very good point Chris. I second that
Joel Martinez
+2  A: 

Check out Joe's answer for the Reflection solution.

I assume you are using Visual Studio.

Are you familiar with the ctrl+shift+r and ctrl+shift+p shortcuts? If not, ctrl+shift+r begins/ends recording a keystroke macro. ctrl+shift+p plays the recorded macro.

What I've done when I have set a lot of properties is to copy the property declarations to where I want them to be set and record a macro for mutating the declaration to a set statement and moving the cursor to the next line, then I just play it until I have all the set statements done.

CrashCodes
Great tip on the macros! Wasn't aware of them before, and have found a use for it already. Thanks.
Winston Smith
Delphi has had this feature for a long time. I was sooo happy when I learned about it. I've encountered other editors that this feature.
CrashCodes
Also check out what happens if you type "if" then hit tab in VS.
CrashCodes
+2  A: 
   ISomeInterface sc = new SomeClass() as ISomeInterface;
   SomeOtherClass soc = new SomeOtherClass();
   foreach (PropertyInfo info in typeof(ISomeInterface)
                                     .GetProperties(BindingFlags.Instance
                                                     |BindingFlags.Public))
   {
       info.SetValue(soc,info.GetValue(sc,null),null);
   }
tvanfosson