LINQ to Objects, .Single<T>() returns copy of/new object and not reference to existing?

  • Thread starter Thread starter Logan S.
  • Start date Start date
L

Logan S.

Using 3.5/SP1, and relatively new to LINQ:

In the following code you can see that I store a collection of objects from
which I later want to update a property of one of the objects.

I thought that .Single<T>(), as used in line 5, would give me a reference
to the object in the collection. But apparently it returns a complete copy
(new object) instead. I'm concluding this because when I update the property
(in line 6), the property of the object declared in line 1 is updated, but
the property of the object in the collection (allSnapInstances) is not
updated. It would be updated if the LINQ query were returning a reference to
that object.

Question: What am I missing? Is there some way I can use LINQ to get a
reference to the object in the collection rather than geting a new/copy? My
intent is to have line 6, below, set the property value on the instance of
the object stored in the collection, allSnapInstances.

1 SnapInfo currentSnapInfo = null;

2 List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;

3 if (allSnapInstances != null)
4 {

5 currentSnapInfo = (from si in allSnapInstances
where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
select si).Single<SnapInfo>();

6 currentSnapInfo.SomeProperty = "some value";
7 }


Thanks!
 
Logan S. said:
Using 3.5/SP1, and relatively new to LINQ:

In the following code you can see that I store a collection of objects
from which I later want to update a property of one of the objects.

I thought that .Single<T>(), as used in line 5, would give me a reference
to the object in the collection. But apparently it returns a complete copy
(new object) instead. I'm concluding this because when I update the
property (in line 6), the property of the object declared in line 1 is
updated, but the property of the object in the collection
(allSnapInstances) is not updated. It would be updated if the LINQ query
were returning a reference to that object.

Question: What am I missing? Is there some way I can use LINQ to get a
reference to the object in the collection rather than geting a new/copy?
My intent is to have line 6, below, set the property value on the instance
of the object stored in the collection, allSnapInstances.

1 SnapInfo currentSnapInfo = null;

2 List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;

3 if (allSnapInstances != null)
4 {

5 currentSnapInfo = (from si in allSnapInstances
where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
select si).Single<SnapInfo>();

6 currentSnapInfo.SomeProperty = "some value";
7 }
I have not encountered the problem of a new copy of an object being created.
And I have objects flying all over the place in collections. I am holding
the objects is session, and I am sending the objects down to the Business
layer where the objects properties are changed.

This is what I do if I want do address the property of an individual object
in a collection.

var currectSnapInfo = from si in allSnapInstances
where
si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID select si;

foreach (var snapi in currectSnapInfo)
{
snapi.property = "hello";
}


Actually, I am doing a return of the object to a high method that is working
with the object in the collection, and passing the collection of objects to
another method, which all objects are the objects of the collection -- no
copy or clone.
 
<snip>

see below:
1 SnapInfo currentSnapInfo = null;

2 List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;

3 if (allSnapInstances != null)
4 {

5 currentSnapInfo = (from si in allSnapInstances
where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
select si).Single<SnapInfo>();

6 currentSnapInfo.SomeProperty = "some value";
7 }

Okay - so I replaced the LINQ query in line 5 with this line:

SnapInfo currentSnapInfo = allSnapInstances.Single(x =>
x.AssociatedSiteComponent.SiteComponentID == currentSiteComponentID);

....and I get my reference directly to the object in allSnapInstances,
rather than some copy of it.

So, while the immediate problem is solved, I'd really appreciate a brief
explanation of the difference between...

1. calling the .Single extension method directly on the allSnapInstances
collection
and
2. the more involved LINQ select, with .Single.

Is it simply the case that a LINQ-to-objects select query always returns a
new collection (i.e., a collection containing *new* objects, that are copies
of the objects in the collection)?

I presume the behavior I have encountered is entirely by design.

Thanks.
 
see below:
1  SnapInfo currentSnapInfo = null;
2  List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;
3  if (allSnapInstances != null)
4  {
5   currentSnapInfo = (from si in allSnapInstances
                     where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
                     select si).Single<SnapInfo>();
6      currentSnapInfo.SomeProperty = "some value";
7   }

Okay - so I replaced the LINQ query in line 5 with this line:

SnapInfo currentSnapInfo = allSnapInstances.Single(x =>
x.AssociatedSiteComponent.SiteComponentID == currentSiteComponentID);

...and  I get my reference directly to the object in allSnapInstances,
rather than some copy of it.

So, while the immediate problem is solved, I'd really appreciate a brief
explanation of the difference between...

1. calling the .Single extension method directly on the allSnapInstances
collection
and
2. the more involved LINQ select, with .Single.

Is it simply the case that a LINQ-to-objects select query always returns a
new collection (i.e., a collection containing *new* objects, that are copies
of the objects in the collection)?

LINQ _never_ does this sort of thing. It operates on _values_ in the
sequence - if values are themselves references, as is the case for
reference types, then it just copies those around. There's no "magic
way" of creating an exact copy of any random .NET type anyway, so how
would it do that?

I do not see how the two code samples could work any different.
However, you haven't shown the code where you check that change of
property is properly reflected in the original object. I strongly
suspect that the problem is there somewhere, not with your LINQ
queries. Can you post a complete short program (i.e. code that can be
cut&pasted and compiled straight away) that demonstrates your
observations?
 
Using 3.5/SP1, and relatively new to LINQ:

In the following code you can see that I store a collection of objects from
which I later want to update a property of one of the objects.

I thought that  .Single<T>(), as used in line 5, would give me a reference
to the object in the collection. But apparently it returns a complete copy
(new object) instead. I'm concluding this because when I update the property
(in line 6), the property of the object declared in line 1 is updated, but
the property of the object in the collection (allSnapInstances) is not
updated. It would be updated if the LINQ query were returning a referenceto
that object.

Question: What am I missing? Is there some way I can use LINQ to get a
reference to the object in the collection rather than geting a new/copy? My
intent is to have line 6, below, set the property value on the instance of
the object stored in the collection, allSnapInstances.

1  SnapInfo currentSnapInfo = null;

2  List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;

3  if (allSnapInstances != null)
4  {

5   currentSnapInfo = (from si in allSnapInstances
                      where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
                      select si).Single<SnapInfo>();

6      currentSnapInfo.SomeProperty = "some value";
7   }

Thanks!

Is SnapInfo a ValueType?
 
Using 3.5/SP1, and relatively new to LINQ:

In the following code you can see that I store a collection of objects from
which I later want to update a property of one of the objects.

I thought that .Single<T>(), as used in line 5, would give me a reference
to the object in the collection. But apparently it returns a complete copy
(new object) instead. I'm concluding this because when I update the property
(in line 6), the property of the object declared in line 1 is updated, but
the property of the object in the collection (allSnapInstances) is not
updated. It would be updated if the LINQ query were returning a reference to
that object.

Question: What am I missing? Is there some way I can use LINQ to get a
reference to the object in the collection rather than geting a new/copy? My
intent is to have line 6, below, set the property value on the instance of
the object stored in the collection, allSnapInstances.

1 SnapInfo currentSnapInfo = null;

2 List<SnapInfo> allSnapInstances = Session["m_AllSnapInstances"] as
List<SnapInfo>;

3 if (allSnapInstances != null)
4 {

5 currentSnapInfo = (from si in allSnapInstances
where si.AssociatedSiteComponent.SiteComponentID ==
currentSiteComponentID
select si).Single<SnapInfo>();

6 currentSnapInfo.SomeProperty = "some value";
7 }

Thanks!

Is SnapInfo a ValueType?

No. If it were, he couldn't have initialized currentSnapInfo with null.

(It was my first thought too.)
 
Back
Top