7

Is there an easy way to basically just get a copy of the data instead of a reference using this method? I tried .ToArray().Where() but that still seems to pass a reference.

Example:

static void Main(string[] args)
{
    List<ob> t = new List<ob>();
    t.Add(new ob() { name = "hello" });
    t.Add(new ob() { name = "test" });

    ob item = t.Where(c => c.name == "hello").First();

    // Changing the name of the item changes the original item in the list<>
    item.name = "burp";

    foreach (ob i in t)
    {
        Console.WriteLine(i.name);
    }

    Console.ReadLine();
}

public class ob
{
    public string name;
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Josh
  • 2,083
  • 5
  • 23
  • 28

4 Answers4

6

You need to create a copy of your ob yourself - it's not something LINQ provides.

Tim Rogers
  • 21,297
  • 6
  • 52
  • 68
  • 3
    Try to implement [IClonable](http://msdn.microsoft.com/en-us/library/system.icloneable%28v=VS.100%29.aspx) by ob type. Then you can use `t.Where(c => c.name == "hello").First().Clone()`. – Petr Behenský Jan 04 '12 at 09:29
6

You could define a Clone method based on the existing protected MemberwiseClone method:

public class Item
{
    public Item Clone()
    {
        return (Item)this.MemberwiseClone();
    }
}

Then:

ob item = t.Where(c => c.name == "hello").First().Clone();
Tudor
  • 61,523
  • 12
  • 102
  • 142
3

As ob is a class, it is a reference type and therefore any instance of ob, when assigned to a different variable (as is happening within the line ob item = t.Where(c => c.name == "hello").First();) will automatically copy the reference to the original instance, and not copy the actual instance itself. This is a general .NET topic regarding object copying and is separate from LINQ/Lambda,

In order to achieve what you want, you'll need to either create a Shallow Copy or a Deep Copy of the resulting instance from your LINQ projection.

For your ob class, a Shallow Copy would suffice (ShallowCopy generally copies as little as possible whereas DeepCopy copies everything - A good reference for the differences can be found here).

To perform a ShallowCopy of an object, you can use a simply MemberwiseClone which is a built-in method of .NET object type, inherited by all objects.

For something more substantial, you'll have to implement your own DeepCopy function, but that can be relatively simple. Something similar to these implementations as specified here and here.

Community
  • 1
  • 1
CraigTP
  • 44,143
  • 8
  • 72
  • 99
1

A much easier way to go is to simply serialize your data to json and then back again. It takes a small performance hit but it is safer as it less error prone and you don't need to modify all your classes.

simply do:

var json = JsonConvert.SerializeObject(myObject)
var clone = JsonConvert.DeserializeObject<T>(json)
Mr W
  • 597
  • 1
  • 7
  • 22
  • 1
    While inelegant, this worked great for dealing with an HttpRuntime.Cache object. Miniscule hit and back to getting things done instead of hunting around for a cloning solution that would also take a performance hit. – Stonetip Mar 10 '16 at 16:15