How to update Object in collection from within foreach

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • peridian
    New Member
    • Dec 2006
    • 72

    #1

    How to update Object in collection from within foreach

    I've got some odd behaviour in a foreach loop, could anybody explain why this occurs?

    Simple class:

    Code:
        public class ImageBindingObject
        {
            public ImageInfo ImageInfo { get; set; }
            public bool Selected { get; set; }
        }
    Simple set of loops:

    Code:
            private void SelectData(IEnumerable<ImageInfo> selected)
            {
                foreach (var image in selected)
                    foreach (var data in activeDataSet)
                        if (image.RelativePath == data.ImageInfo.RelativePath)
                            data.Selected = true;
            }
    If I inspect the data object after the condition is met, data.Selected is indeed set to true, but when I inspect the activeDataSet, none of the objects have the Selected property set to true.

    Why are the changes to the content of the collection not being reflected within the collection itself? I need to access the collection from elsewhere after this has run, and the flags are never set, and it's not that the condition in this code is never true.

    Regards,
    Rob.
  • Christian Binder
    Recognized Expert New Member
    • Jan 2008
    • 218

    #2
    Originally posted by peridian
    I've got some odd behaviour in a foreach loop, could anybody explain why this occurs?

    Simple class:

    Code:
        public class ImageBindingObject
        {
            public ImageInfo ImageInfo { get; set; }
            public bool Selected { get; set; }
        }
    Simple set of loops:

    Code:
            private void SelectData(IEnumerable<ImageInfo> selected)
            {
                foreach (var image in selected)
                    foreach (var data in activeDataSet)
                        if (image.RelativePath == data.ImageInfo.RelativePath)
                            data.Selected = true;
            }
    If I inspect the data object after the condition is met, data.Selected is indeed set to true, but when I inspect the activeDataSet, none of the objects have the Selected property set to true.

    Why are the changes to the content of the collection not being reflected within the collection itself? I need to access the collection from elsewhere after this has run, and the flags are never set, and it's not that the condition in this code is never true.

    Regards,
    Rob.
    What's the type of activeDataSet? How is it filled?

    Comment

    • peridian
      New Member
      • Dec 2006
      • 72

      #3
      Sorry, forgot that. It's a private member in the class:

      private IEnumerable<Ima geBindingObject > activeDataSet;

      Gets set in the constructor:

      activeDataSet = new List<ImageBindi ngObject>();

      Populated in another method:

      Code:
              private bool RefreshData()
              {
                  var images = wrap.Get();
                  ....
                  activeDataSet = images.Select(img => new ImageBindingObject()
                                                       {
                                                           ImageInfo = img,
                                                           Selected = false
                                                       });
                  ....
              }

      Comment

      • Christian Binder
        Recognized Expert New Member
        • Jan 2008
        • 218

        #4
        Originally posted by peridian
        Sorry, forgot that. It's a private member in the class:

        private IEnumerable<Ima geBindingObject > activeDataSet;

        Gets set in the constructor:

        activeDataSet = new List<ImageBindi ngObject>();

        Populated in another method:

        Code:
                private bool RefreshData()
                {
                    var images = wrap.Get();
                    ....
                    activeDataSet = images.Select(img => new ImageBindingObject()
                                                         {
                                                             ImageInfo = img,
                                                             Selected = false
                                                         });
                    ....
                }
        Ok, I think your problem is, that each time you access activeDataSet there will be created a new ImageBindingObj ect (it's because of LinQ's Select() method)

        Try the following (note the ToList() at the end):
        Code:
        activeDataSet = images.Select(img => new ImageBindingObject()
                                                        {
                                                              ImageInfo = img,
                                                              Selected = false
                                                         }).ToList();

        Comment

        • peridian
          New Member
          • Dec 2006
          • 72

          #5
          That worked! Thanks.

          I am intrigued though, are there any articles explaining this behaviour?

          Why would the collection recreate new objects when I access it even though it's long after the Select was called?

          Regards,
          Rob.

          Comment

          • Christian Binder
            Recognized Expert New Member
            • Jan 2008
            • 218

            #6
            Maybe you google for information regarding this problem/behaviour.

            I'm working a lot with LinQ (because it's cool stuff ;) and I'm facing this kind of problem often, but it can cost a lot of work to find out, what's wrong.

            Why does this happen?
            If you define
            var test = collection.Sele ct(x => new Y(x));
            test doesn't contain the results, it contains only information how to obtain them. In this case, test only knows, it should iterate over collection and for each found element of collection it applies "make new Y by element".

            So the definition doesn't take any time, although e.g. new Y(x) would take 10 seconds because of doing heavy operations.

            The work will be done when you need the values, because you iterate over it in for-each-loop for example (GetEnumerator( ) will be called internally which applys the lambda-expression which you've passed to Select() ).

            And each time you request the Enumerator (due to for-each), the Select()-lambda will be applied to each of collection's items and a new Y-object will be created.

            But if you call IEnumerable's ToList()-method, a List of Y will be created and when you iterate over it, there won't be any further creation of Y's.

            I hope, this is at least a little bit understandably :-)

            Comment

            • peridian
              New Member
              • Dec 2006
              • 72

              #7
              Thanks, that clarifies it.

              Rob.

              Comment

              Working...