LINQ - Does the Where expression return new instance or reference to object instance
This is probably a basic question for some, but it affects how I design a piece of my program.
I have a single collection of type A:
IEnumerable<A> myCollection;
I am filtering my collection on 2 different criteria:
IEnumerable<A> subCollection1 = myCollection.Where(x => x.Count > 10);
etc.
Now, I know that the .Where expression will return a new instance of IEnumerabl开发者_Python百科e, but does the new collection contain the same reference to an instance of type A that 'myCollection' references, or are new copies of type A created? If new instances of type 'A' are created, is there a way to say that 'subCollection1' references the same instances of A as 'myCollection' references?
Edit: To Add further clarification.
I am looking for a way so that when I make a change to an instance of 'A' in 'subCollection1', that it is also modified for 'myCollection'.
The instances are the same if they are classes, but copies if they are structs/value types.
int, byte and double are value types, as are structs (like System.Drawing.Point
and self-defined structs).
But strings, all of your own classes, basically "the rest", are reference types.
Note: LINQ uses the same rules as all other assignments.
For objects:
Person p1 = new Person();
p1.Name = "Mr Jones";
Person p2 = p1;
p2.Name = "Mr Anderssen";
// Now p1.Name is also "Mr Anderssen"
For structs:
Point p1 = new Point();
p1.x = 5;
Point p2 = p1;
p2.x = 10;
// p1.x is still 5
The same rules apply when using LINQ.
Actually it depends on the collection. In some cases, LINQ methods can return cloned objects instead of references to originals. Take a look at this test:
[Test]
public void Test_weird_linq()
{
var names = new[]{ "Fred", "Roman" };
var list = names.Select(x => new MyClass() { Name = x });
list.First().Name = "Craig";
Assert.AreEqual("Craig", list.First().Name);
}
public class MyClass
{
public string Name { get; set; }
}
This test will fail, even though many people believe that the same object will be returned by list.First()
. It will work if you use another collection "modified with ToList()
".
var list = names.Select(x => new MyClass() { Name = x }).ToList();
I don't know for sure why it works this way, but it's something to have in mind when you write your code :)
This question can help you understand how LINQ works internally.
They are same objects. Where
only filters, Select
produces (can produce) new instances.
Making a new object that is a reference type is non-trivial. LINQ would have no idea how to do it. LINQ always returns the same instances when dealing with reference types.
I just wanted to add to some of the other answers -- in general, when I'm not sure of something but require a particular behavior, I'll add a unit test for it. You could easily put this into a test and then check for equality, which will tell you if you're looking at a reference of the object in the original container. Some may argue that this is stupid because you "should just know" what happens, but for me I know I will either be 1) unsure because I'm not an awesome programmer, and 2) there are always nights where I have to burn the midnight oil, and it's good to have the reassurance that something behaves as you need it to.
精彩评论