Ошибка наблюдения ObservableCollection [дубликат]

A - Объяснение

Вы можете использовать библиотеки Jackson для привязки JSON String к экземплярам POJO ( Обычный объект Java ). POJO - это просто класс с только частными полями и общедоступными методами getter / setter. Джексон собирается пересечь методы (используя отражение) и отображает объект JSON в экземпляр POJO, поскольку имена полей класса соответствуют именам полей объекта JSON.

В вашем объекте JSON, который на самом деле является составным объектом, основной объект состоит из двух под-объектов. Итак, наши классы POJO должны иметь одинаковую иерархию. Я назову весь объект JSON как объект страницы. Объект страницы состоит из объекта PageInfo и массива объектов Post.

Итак, мы должны создать три разных класса POJO:

  • Класс страницы, составной элемент PageInfo Class и массив сообщений экземпляров
  • PageInfo Class
  • Posts Class

Единственным пакетом, который я использовал, является Jackson ObjectMapper, то, что мы делаем, является обязательными данными ;

com.fasterxml.jackson.databind.ObjectMapper

Необходимые зависимости, файлы jar перечислены ниже:

  • jackson-core-2.5.1.jar
  • jackson- databind-2.5.1.jar
  • jackson-annotations-2.5.0.jar

Вот требуемый код:

B - Main POJO Класс: Страница

package com.levo.jsonex.model;

public class Page {

    private PageInfo pageInfo;
    private Post[] posts;

    public PageInfo getPageInfo() {
        return pageInfo;
    }

    public void setPageInfo(PageInfo pageInfo) {
        this.pageInfo = pageInfo;
    }

    public Post[] getPosts() {
        return posts;
    }

    public void setPosts(Post[] posts) {
        this.posts = posts;
    }

}

C - дочерний класс POJO: PageInfo

package com.levo.jsonex.model;

public class PageInfo {

    private String pageName;
    private String pagePic;

    public String getPageName() {
        return pageName;
    }

    public void setPageName(String pageName) {
        this.pageName = pageName;
    }

    public String getPagePic() {
        return pagePic;
    }

    public void setPagePic(String pagePic) {
        this.pagePic = pagePic;
    }

}

D - дочерний класс POJO: сообщение

package com.levo.jsonex.model;

public class Post {

    private String post_id;
    private String actor_id;
    private String picOfPersonWhoPosted;
    private String nameOfPersonWhoPosted;
    private String message;
    private int likesCount;
    private String[] comments;
    private int timeOfPost;

    public String getPost_id() {
        return post_id;
    }

    public void setPost_id(String post_id) {
        this.post_id = post_id;
    }

    public String getActor_id() {
        return actor_id;
    }

    public void setActor_id(String actor_id) {
        this.actor_id = actor_id;
    }

    public String getPicOfPersonWhoPosted() {
        return picOfPersonWhoPosted;
    }

    public void setPicOfPersonWhoPosted(String picOfPersonWhoPosted) {
        this.picOfPersonWhoPosted = picOfPersonWhoPosted;
    }

    public String getNameOfPersonWhoPosted() {
        return nameOfPersonWhoPosted;
    }

    public void setNameOfPersonWhoPosted(String nameOfPersonWhoPosted) {
        this.nameOfPersonWhoPosted = nameOfPersonWhoPosted;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public int getLikesCount() {
        return likesCount;
    }

    public void setLikesCount(int likesCount) {
        this.likesCount = likesCount;
    }

    public String[] getComments() {
        return comments;
    }

    public void setComments(String[] comments) {
        this.comments = comments;
    }

    public int getTimeOfPost() {
        return timeOfPost;
    }

    public void setTimeOfPost(int timeOfPost) {
        this.timeOfPost = timeOfPost;
    }

}

E - Пример файла JSON: sampleJSONFile.json

Я только что скопировал ваш образец JSON в этот файл и поместил его в папку проекта.

{
   "pageInfo": {
         "pageName": "abc",
         "pagePic": "http://example.com/content.jpg"
    },
    "posts": [
         {
              "post_id": "123456789012_123456789012",
              "actor_id": "1234567890",
              "picOfPersonWhoPosted": "http://example.com/photo.jpg",
              "nameOfPersonWhoPosted": "Jane Doe",
              "message": "Sounds cool. Can't wait to see it!",
              "likesCount": "2",
              "comments": [],
              "timeOfPost": "1234567890"
         }
    ]
}

F - Демо-код

package com.levo.jsonex;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.levo.jsonex.model.Page;
import com.levo.jsonex.model.PageInfo;
import com.levo.jsonex.model.Post;

public class JSONDemo {

    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            Page page = objectMapper.readValue(new File("sampleJSONFile.json"), Page.class);

            printParsedObject(page);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void printParsedObject(Page page) {
        printPageInfo(page.getPageInfo());
        System.out.println();
        printPosts(page.getPosts());
    }

    private static void printPageInfo(PageInfo pageInfo) {
        System.out.println("Page Info;");
        System.out.println("**********");
        System.out.println("\tPage Name : " + pageInfo.getPageName());
        System.out.println("\tPage Pic  : " + pageInfo.getPagePic());
    }

    private static void printPosts(Post[] posts) {
        System.out.println("Page Posts;");
        System.out.println("**********");
        for(Post post : posts) {
            printPost(post);
        }
    }

    private static void printPost(Post post) {
        System.out.println("\tPost Id                   : " + post.getPost_id());
        System.out.println("\tActor Id                  : " + post.getActor_id());
        System.out.println("\tPic Of Person Who Posted  : " + post.getPicOfPersonWhoPosted());
        System.out.println("\tName Of Person Who Posted : " + post.getNameOfPersonWhoPosted());
        System.out.println("\tMessage                   : " + post.getMessage());
        System.out.println("\tLikes Count               : " + post.getLikesCount());
        System.out.println("\tComments                  : " + Arrays.toString(post.getComments()));
        System.out.println("\tTime Of Post              : " + post.getTimeOfPost());
    }

}

G - демонстрационный выход

Page Info;
****(*****
    Page Name : abc
    Page Pic  : http://example.com/content.jpg
Page Posts;
**********
    Post Id                   : 123456789012_123456789012
    Actor Id                  : 1234567890
    Pic Of Person Who Posted  : http://example.com/photo.jpg
    Name Of Person Who Posted : Jane Doe
    Message                   : Sounds cool. Can't wait to see it!
    Likes Count               : 2
    Comments                  : []
    Time Of Post              : 1234567890
701
задан cdonner 5 July 2014 в 03:57
поделиться

12 ответов

Что может случиться, так это то, что SignalData косвенно меняет словарь подписчиков под капотом во время цикла и приводит к этому сообщению. Вы можете проверить это, изменив

foreach(Subscriber s in subscribers.Values)

To

foreach(Subscriber s in subscribers.Values.ToList())

Если я прав, проблема исчезнет

1288
ответ дан JaredPar 27 August 2018 в 13:48
поделиться

Примечание. В целом коллекции .Net не поддерживают перечисление и изменение в одно и то же время. Если вы попытаетесь изменить список коллекции, пока находитесь в середине перечисления, это вызовет исключение.

Таким образом, проблема этой ошибки заключается в том, что мы не можем изменять список / словарь во время цикла через. Но если мы итерируем словарь, используя временный список его ключей, мы можем изменить словарь, потому что теперь мы не итерируем словарь (и итерируем его коллекцию ключей).

sample:

//get key collection from dictionary into a list to loop through
List<int> keys = new List<int>(Dictionary.Keys);

// iterating key collection using simple for-each loop
foreach (int key in keys)
{
  // Now we can perform any modification with values of dictionary.
  Dictionary[key] = Dictionary[key] - 1;
}

Вот сообщение в блоге об этом решении.

И для глубокого погружения в stackoverflow: Почему эта ошибка возникает? ]

9
ответ дан Community 27 August 2018 в 13:48
поделиться

Таким образом, другой способ решить эту проблему был бы вместо того, чтобы удалять элементы, создающие новый словарь, и добавлять только те элементы, которые вы не хотели удалить, а затем заменить исходный словарь на новый. Я не думаю, что это слишком большая проблема эффективности, потому что она не увеличивает количество раз, когда вы перебираете структуру.

0
ответ дан ford prefect 27 August 2018 в 13:48
поделиться

На самом деле проблема заключается в том, что вы удаляете элементы из списка и ожидаете продолжить чтение списка, как будто ничего не случилось.

Что вам действительно нужно сделать, так это начать с конца и обратно к началу. Даже если вы удалите элементы из списка, вы сможете продолжить чтение.

4
ответ дан luc.rg.roy 27 August 2018 в 13:48
поделиться

Хорошо, так что помогло мне повторить назад. Я пытался удалить запись из списка, но итерации вверх, и это закрутило цикл, потому что запись больше не существовала:

for (int x = myList.Count - 1; x > -1; x--)
                        {

                            myList.RemoveAt(x);

                        }
1
ответ дан Mark Aven 27 August 2018 в 13:48
поделиться

Я видел много вариантов для этого, но для меня этот был лучшим.

ListItemCollection collection = new ListItemCollection();
        foreach (ListItem item in ListBox1.Items)
        {
            if (item.Selected)
                collection.Add(item);
        }

Затем просто прокрутите коллекцию.

Имейте в виду, что ListItemCollection может содержать дубликаты. По умолчанию в сборнике ничего не мешает дублированию. Чтобы избежать дублирования, вы можете сделать это:

ListItemCollection collection = new ListItemCollection();
            foreach (ListItem item in ListBox1.Items)
            {
                if (item.Selected && !collection.Contains(item))
                    collection.Add(item);
            }
2
ответ дан Mike 27 August 2018 в 13:48
поделиться

Когда абонент отказывается от подписки, вы меняете содержимое коллекции подписчиков во время перечисления.

Существует несколько способов исправить это, один из которых меняет цикл for, чтобы использовать явный .ToList():

public void NotifySubscribers(DataRecord sr)  
{
    foreach(Subscriber s in subscribers.Values.ToList())
    {
                                              ^^^^^^^^^  
        ...
95
ответ дан Mitch Wheat 27 August 2018 в 13:48
поделиться

Вы также можете заблокировать словарь подписчиков, чтобы он не изменялся всякий раз, когда он был зациклен:

 lock (subscribers)
 {
         foreach (var subscriber in subscribers)
         {
               //do something
         }
 }
33
ответ дан Mohammad Sepahvand 27 August 2018 в 13:48
поделиться

InvalidOperationException - произошло событие InvalidOperationException. Он сообщает, что «коллекция была изменена» в foreach-loop

Использовать оператор break, После удаления объекта.

ex:

ArrayList list = new ArrayList(); 

foreach (var item in list)
{
    if(condition)
    {
        list.remove(item);
        break;
    }
}
3
ответ дан nich 27 August 2018 в 13:48
поделиться

У меня была такая же проблема, и она была решена, когда я использовал цикл for вместо foreach.

// foreach (var item in itemsToBeLast)
for (int i = 0; i < itemsToBeLast.Count; i++)
{
    var matchingItem = itemsToBeLast.FirstOrDefault(item => item.Detach);

   if (matchingItem != null)
   {
      itemsToBeLast.Remove(matchingItem);
      continue;
   }
   allItems.Add(itemsToBeLast[i]);// (attachDetachItem);
}
2
ответ дан Nisarg Shah 27 August 2018 в 13:48
поделиться

Вы можете скопировать объект словаря подписчиков на объект временного словаря того же типа, а затем перебрать временный объект словаря с помощью цикла foreach.

0
ответ дан Rezoan 27 August 2018 в 13:48
поделиться

Более эффективным способом, на мой взгляд, является наличие другого списка, в котором вы заявляете, что вы помещаете все, что нужно «удалить». Затем, после завершения основного цикла (без .ToList ()), вы делаете еще один цикл над списком «для удаления», удаляя каждую запись, когда это происходит. Итак, в своем классе вы добавляете:

private List<Guid> toBeRemoved = new List<Guid>();

Затем вы меняете его на:

public void NotifySubscribers(DataRecord sr)
{
    toBeRemoved.Clear();

    ...your unchanged code skipped...

   foreach ( Guid clientId in toBeRemoved )
   {
        try
        {
            subscribers.Remove(clientId);
        }
        catch(Exception e)
        {
            System.Diagnostics.Debug.WriteLine("Unsubscribe Error " + 
                e.Message);
        }
   }
}

...your unchanged code skipped...

public void UnsubscribeEvent(Guid clientId)
{
    toBeRemoved.Add( clientId );
}

Это не только решит вашу проблему, это не позволит вам продолжать создавать список из вашего словаря, который стоит дорого, если там много подписчиков. Предполагая, что список абонентов, которые будут удалены на любой заданной итерации, будет меньше, чем общее число в списке, это должно быть быстрее. Но, конечно, не стесняйтесь профилировать его, чтобы быть уверенным, что это так, если есть какие-либо сомнения в вашей конкретной ситуации использования.

53
ответ дан Soner Gönül 27 August 2018 в 13:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: