Question

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.

Was it helpful?

Solution

"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.

OTHER TIPS

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.

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.

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

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.

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.

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().

   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);
   }

I did like the following and it works just very well to convert from one object into another using implicit operator:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello");
            ExecutionReport er = new ExecutionReport("ORDID1234",3000.43,DateTime.UtcNow);
            Order ord = new Order();
            ord = er;
            Console.WriteLine("Transferred values are : " + er.OrderId + "\t" + ord.Amount.ToString() + "\t" + ord.TimeStamp.ToString() + "\t");
            Console.ReadLine();
        }
    }


    public  class Order
    {
        public string OrderId { get; set; }
        public double Amount { get; set; }
        public DateTime TimeStamp { get; set; }
        public static implicit operator ExecutionReport(Order ord)
        {
            return new ExecutionReport()
            {
                OrderId = ord.OrderId,
                Amount = ord.Amount,
                TimeStamp = ord.TimeStamp
            };
        }
        public static implicit operator Order(ExecutionReport er)
        {
            return new Order()
            {
                OrderId = er.OrderId,
                Amount = er.Amount,
                TimeStamp = er.TimeStamp
            };
        }

        public Order()
        { }
    }

    public  class ExecutionReport
    {
        public string OrderId { get; set; }
        public double Amount { get; set; }
        public DateTime TimeStamp { get; set; }
        public ExecutionReport() { }
        public ExecutionReport(string orderId,double amount, DateTime ts)
        {
            OrderId = orderId; Amount = amount; TimeStamp = ts;
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top