6

I have a class

public class Car()
{
    public string Name;
    public string Model;
}

And i have a property

List<Car> CarsA = new List<Car>();
CarsA.Add(new Car(){Name = "Verna",Model="Hyundai"});
CarsA.Add(new Car(){Name = "X1",Model="Bmw"});

and i have another property

List<Car> CarsB = new List<Car>();

Now i want to add clone/copy all the entries from CarsA to CarsB without taking CarsA properties current instances

(i.e. i want to create new object for each entry and add it).

Something like

foreach(var car in CarsA)
{
    Car newCar =new Car();
    newCar.Name = car.Name;
    newCar.Model = car.Model;
    CarsB.Add(newCar);
}

What if i don't want to implement ICloneable and i don't have a copy contructor?

Vivek Saurav
  • 2,235
  • 4
  • 25
  • 46

3 Answers3

6

You could probably consider LINQ solution:

List<Car> CarsB = (from c in CarsA
                    let a = new Car() { Name = c.Name, Model = c.Model }
                    select a).ToList();

Since Name and Model are of string type (which is immutable), this operation is safe.

It is quite readable, I think.

Same but with query syntax:

CarsB = CarsA.Select(c => new Car(){ Name = c.Name, Model = c.Model }).ToList();

Note: If, suppose, the Model is not string but a class, then the operation above a = new Car() must be slightly change to something which really clone all the items in the model (something like this: Model = c.Model.Clone()) and not just referring to it (Model = c.Model)

Ian
  • 30,182
  • 19
  • 69
  • 107
  • yea it's readable but still i have to write all the properties in LinQ query too. – Vivek Saurav Jan 28 '16 at 14:52
  • @VivekSaurav are you saying you want to have general solution without writing the properties in the LINQ? – Ian Jan 28 '16 at 14:53
  • @VivekSaurav In that case then, I believe the extension IClonable method is the best: http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c?lq=1 This is already going as generic as it can be, I think. – Ian Jan 28 '16 at 14:59
  • As an aside, no string is copied in your solution. (Which is ok because strings are immutable and hence can only be replaced in the new `Car`, not altered). – Peter - Reinstate Monica Jan 28 '16 at 15:07
  • @PeterA.Schneider ah, I actually am looking for the correct word. I put "copied" in distinction with "referred" (like what happen in normal class). Not to sure if "copied" is the correct technical term. Or since string is immutable I should use different term? I thought "copied" was quite proper since it is altogether new string put in the `new Car()` – Ian Jan 28 '16 at 15:10
  • The thing is that you copy the string references (which is the correct technical expression), i.e. you perform a *shallow* copy of the strings. That would hurt for members which do not have immutable types because the copy could alter (not replace!) the member and alter the original's member, too. Strings cannot be altered, they are always replaced, so that refering to the same string is ok. (But imagine the cars had a reference to a gas tank with properties like gallons and octane; you would have to deep-copy the tank, or two cars would use up the same tank.) – Peter - Reinstate Monica Jan 28 '16 at 15:16
  • @PeterA.Schneider thanks for your input! I have just edited my post to make it less ambiguous and use the more technical term "immutable" for `string`. – Ian Jan 28 '16 at 15:23
3

If you want to do a deep copy your instances serializing to JSON and then back is an option you could consider.

This however will require a lot more performance than implementing copy methods for all objects to be copied. However it saves a lot of time writing copy methods, and even though it might be hundred's of times slower it's still fast.

I use to solve this with Json.net using an extension method looking something like this:

public static T Clone<T>(this T source)
{
    if (Object.ReferenceEquals(source, null))
        return default(T);

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}

This can also be done with other types of serialization(that does not require 3rd party libs) as pointed out by Scott Chamberlain, example with BinaryFormatter: (Also note when going with this approach your class has to be annotated with the [Serializable] attribute)

public static T Clone<T>(this T source)
{
    if (Object.ReferenceEquals(source, null))
        return default(T);

    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter();
        formatter.Serialize(stream, source);
        stream.Position = 0;

        return (T) formatter.Deserialize(stream);
    }
}

Usage would then be:

foreach(var car in CarsA)
{
    CarsB.Add(car.Clone<Car>());
}

It could also be used like:

List<Car> CarsB = CarsA.Clone<List<Car>>();
Simon Karlsson
  • 4,090
  • 22
  • 39
  • 3
    You don't need the 3rd party dependency, I often use this exact same pattern but use [`BinaryFormatter`](https://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter(v=vs.110).aspx) instead of `JsonConvert`. – Scott Chamberlain Jan 28 '16 at 14:53
  • @ScottChamberlain Just realized why I allways end up with the json way, when using `BinaryFormatter` you have to tag your classes with `[Serializable]`. – Simon Karlsson Jan 28 '16 at 15:16
1

Simplified Linq

var CarsB = CarsA.Cast<Car>().ToList();

The nice thing about the Cast<>ing is that if you have different types that have similar structure, interface, etc, it will copy the respective elements as the new instanced list.

DRapp
  • 47,638
  • 12
  • 72
  • 142