Link to home
Start Free TrialLog in
Avatar of trowa
trowa

asked on

C# copy object?

I got some simple classes like below:

public class testClass
    {
        public int Id { get; set; }
        public string Property1 { get; set; }
        public string Property2 { get; set; }
        public string Property3 { get; set; }
    }
    public class testClassExtra
    {
        public int Id { get; set; }
        public string Property1 { get; set; }
        public string Property2 { get; set; }
        public string Property3 { get; set; }
        public string Property4 { get; set; }
        public string Property5 { get; set; }
    }

Open in new window


Let's say I got an instance of class testClassExtra:

testClassExtra test = new testClassExtra();
            test.Id = 1;
            test.Property1 = "Property1";
            test.Property2 = "Property2";
            test.Property3 = "Property3";
            test.Property4 = "Property4";
            test.Property5 = "Property5";

Open in new window


How can I have:

testClass test2 = new testClass();

Open in new window


then to copy the values from testClassExtra test?

I don't want to do something like this:

test2.Id = test.Id;
            test2.Property1 = test.Property1;
            test2.Property2 = test.Property2;
            test2.Property3 = test.Property3;

Open in new window


Is that possible?

Thank you.
Avatar of trowa
trowa

ASKER

I think I found a solution:

public static class MissingExtensions
    {
        public static void CopyTo(this object S, object T)
        {
            foreach (var pS in S.GetType().GetProperties())
            {
                foreach (var pT in T.GetType().GetProperties())
                {
                    if (pT.Name != pS.Name) continue;
                    (pT.GetSetMethod()).Invoke(T, new object[] { pS.GetGetMethod().Invoke(S, null) });
                }
            };
        }
    }

Open in new window

Avatar of AndyAinscow
A standard way of doing this is to use a copy constructor.

TestClass(TestClassExtra ob)
{
  Id = ob.Id;
  Property1 = ob.Property1;
}

so you would have something like this
TestClassExtra tce = new testClassExtra();
tce.Id = 1;
...

TestClass tc = new TestClass(tce);
Avatar of trowa

ASKER

Hi Andy,

I should mention this earlier, I can't use that "standard" method as I got a lot of classes which look similar. By doing so I need to copy all the properties of the classes to another one, that bring me 2 issues:
1. Time consuming to create those scripts
2. I'm afraid I would miss out some of it, or when there are additional properties being added, which I try to avoid.

Thank you
OK.  Don't forget if it was suitable you could implement code like your copy routine in the copy constructor.

ps.  similar classes - would inheritance be useful if you don't use it at present?
you could implement code like your copy routine in the copy constructor.

would inheritance be useful if you don't use it at present?

if you would make TestClass baseclass of TestClassExtra, your requirements might be done easier:

    public class TestClass
    {
        public int Id { get; set; }
        public string Property1 { get; set; }
        public string Property2 { get; set; }
        public string Property3 { get; set; }

       // copy constructor
       public TestClass(TestClass toCopy)
       {
               id               = toCopy.id;
               Property1 = toCopy.Property1;
               Property2 = toCopy.Property2;
               Property3 = toCopy.Property3;
        }
   public class TestClassExtra : public TestClass
   {
        public string Property4 { get; set; }
        public string Property5 { get; set; }
   }

Open in new window


then you could do

  testClassExtra testEx = new testClassExtra();
  testEx.Id = 1;
  testEx.Property1 = "Property1";
  testEx.Property2 = "Property2";
  testEx.Property3 = "Property3";
  testEx.Property4 = "Property4";
  testEx.Property5 = "Property5";

   // cast testEx object to its baseclass object and use copy constructor of TestClass to assign the id and properties
  TestClass test = new TestClass((TestClass)testEx); 

Open in new window


Sara
Avatar of trowa

ASKER

Hi Sara,

Knowing I can do that by using similar method you have showing above, but the idea behind my intention is not to repetitively write the whole similar codes.

Thank you.
my intention is not to repetitively write the whole similar codes.

unfortunately c# has no generic copy constructor or assignment operator (like c++).

but i found sample code how to write a generic clone function which could be used to copy all members into a new copy object:

public static class Extension
{
    public static T CreateCopy<T>(this T src)
        where T: new()
    {
        if (src == null) return default(T); // just return null
        T tgt = new T(); // create new instance
        // then copy all properties
        foreach (var pS in src.GetType().GetProperties())
        {
            foreach (var pT in tgt.GetType().GetProperties())
            {
                if (pT.Name != pS.Name) continue;
                (pT.GetSetMethod()).Invoke(tgt, new object[] { 
                    pS.GetGetMethod().Invoke(src, null) });
            }
        };
        return tgt;
    } // method
} // class

Open in new window


this template function was used like that

Customer CopyCustomerWithNewPK(Customer item)
{
    Customer newItem = item.CreateCopy(); // use ext. method to copy properties
    newItem.CustomerId = new Guid(); // create new primary key for the item
    return newItem;
}

Open in new window


note, the above would generate a new id for the customer (PK). that probably has to be considered  with your approach as well.

you may find this and more samples by searching for 'c# automatic copy constructor'.

Sara
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of trowa

ASKER

Hi -saige-

I was trying your first suggestion in ID: 42396126:

static class Extensions
    {
        public static T CopyTo<S, T>(this S source) where T : class, new()
        {
            T target = Activator.CreateInstance<T>();
            foreach (var s_prop in typeof(S).GetProperties(System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
            {
                var t_prop = typeof(T).GetProperty(s_prop.Name);
                if (t_prop != null && t_prop.CanWrite)
                {
                    try
                    {
                        t_prop.SetValue(target, s_prop.GetValue(source, null));
                    }
                    catch (Exception)
                    {
                        // There was a problem setting the value of the property 
                        // in the target object.  Log it, handle it or both.
                    }
                }
            }
            return target;
        }
    }

Open in new window


but I getting error below.

Error	1	No overload for method 'SetValue' takes 2 arguments

Open in new window


I'm using VS 2010, what modification need to be made to compatible in this environment?

Thank you.
Avatar of trowa

ASKER

Hi -saige-

I have solved my issue above by passing a 3rd parameter with null value.

But I must say that you're very knowledgeable in .NET programming!! Are you a lecturer that teaching .NET programming or someone whom got lots of hands-on experiences in .NET programming?

Thank you
Avatar of trowa

ASKER

By the way, may I know what does this line of code means?

public static T CopyTo<S, T>(this S source, T target) where T : class, new()

Open in new window


Thank you
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of trowa

ASKER

Thanks for the assistance