none
[C#] Verificar itens antes de uma List RRS feed

  • Pergunta

  • Bom dia galera, beleza? Tenho um ListBox e queria verificar itens antes de adicioná-los.

    Classe para divisão de dados:

    public class Info
        {
            public String Nome { get; set; }
            public decimal Valor { get; set; }
    
            public Info() { }
    
            public Info(string nome, decimal valor)
            {
                this.Nome = nome;
                this.Valor = valor;
            }
        }

    Método para adicionar novo item:

    List<Info> Produtos = new List<Info>();
    
    Produtos.Add(new Info()
                    {
                        Nome = "Teste",
                        Valor = 12
                    });

    Método para pegar itens da List:

    foreach (Info produto in Produtos)
                {
                    MessageBox.Show(string.Format("Produto: {0}\n Valor: {1}", produto.Nome, produto.Valor));
                }

    Tentei verificar usando contains no PRODUTO dentro do foreach mas retonar sem valor. Como fazer isso?


    domingo, 19 de junho de 2016 14:15

Respostas

  • O "Contains" do List não vai achar porque você não tem o mesmo objeto para procurar.

    O que o "Contains" faz é comparar a REFERÊNCIA do objeto (em caso de classes) para determinar se é a mesma. Então isso:

    Info A = new Info("Nome 1", 10m);
    //esse tem a mesma REFERÊNCIA que "A"
    Info B = A;
    Info C = new Info("Nome 2", 20m);
    //veja que é igual a A
    //mas NÂO É "A", tem os mesmo valores,
    //mas não a mesma referência
    Info D = new Info("Nome 1", 10m);
    
    List<Info> Produtos = new List<Info>();
    Produtos.Add(A);
    Produtos.Add(C);
    
    //Se você usar o "Contains(B)" vai retornar
    //positivo, pois B é igual a A.
    
    //No entanto "Contains(D)" vai retornar
    //negativo, pois D NÃO É "A", mesmo sendo
    //igual em suas propriedades

    Como você pode ver aqui ReferenceSource, "Contains()" chama o método "Equals()" da classe. Toda classe derivada de object (ou seja, toda classe) usa o método do object para resolver o Equals, que é basicamente comparar a referência da classe. Se você rescrever esse método, poderá alterar essa decisão para comparar propriedades apenas. Outra alternativa é fazer um "foreach" você mesmo. O "Contains()" basicamente faz isso, um "foreach" e cada objeto rodando o método "Equals()" dele.

    //Código do Contains (veja o link que pus anteriomente)
    public virtual bool Contains(Object item)
    {
        if (item==null)
        {
            for (int i = 0; i < _size; i++)
                if (_items[i]==null) return true;
            return false;
        }
        else
        {
            for(int i=0; i<_size; i++)
                if ((_items[i] != null) && (_items[i].Equals(item))) return true;
            return false;
        }
    }
    
    //Seu "foreach"
    public bool Contains(List<Info> Produtos, Info Item)
    {
        if (Item == null)
        {
            //Faça o mesmo? Ou não pode ser null nunca ...
            //Ai você decide
        }
        foreach (Info Existing in Produtos)
            if (Existing.Nome == Item.Nome && Existing.Valor == Existing.Valor) return true;
        //Era para comparar o valor também ou só o nome?
        return false;
    }

    Entendeu o exemplo?

    • Sugerido como Resposta SammuelMiranda segunda-feira, 20 de junho de 2016 12:14
    • Marcado como Resposta Thales F Quintas segunda-feira, 20 de junho de 2016 13:39
    segunda-feira, 20 de junho de 2016 12:14

Todas as Respostas

  • Bom dia,

    Poderia exemplificar? Não consegui entender sua dúvida...

    Att,


    Se a resposta contribuiu com seu aprendizado por favor marque como util, se solucionou seu problema marque como resposta.

    segunda-feira, 20 de junho de 2016 11:22
  • O "Contains" do List não vai achar porque você não tem o mesmo objeto para procurar.

    O que o "Contains" faz é comparar a REFERÊNCIA do objeto (em caso de classes) para determinar se é a mesma. Então isso:

    Info A = new Info("Nome 1", 10m);
    //esse tem a mesma REFERÊNCIA que "A"
    Info B = A;
    Info C = new Info("Nome 2", 20m);
    //veja que é igual a A
    //mas NÂO É "A", tem os mesmo valores,
    //mas não a mesma referência
    Info D = new Info("Nome 1", 10m);
    
    List<Info> Produtos = new List<Info>();
    Produtos.Add(A);
    Produtos.Add(C);
    
    //Se você usar o "Contains(B)" vai retornar
    //positivo, pois B é igual a A.
    
    //No entanto "Contains(D)" vai retornar
    //negativo, pois D NÃO É "A", mesmo sendo
    //igual em suas propriedades

    Como você pode ver aqui ReferenceSource, "Contains()" chama o método "Equals()" da classe. Toda classe derivada de object (ou seja, toda classe) usa o método do object para resolver o Equals, que é basicamente comparar a referência da classe. Se você rescrever esse método, poderá alterar essa decisão para comparar propriedades apenas. Outra alternativa é fazer um "foreach" você mesmo. O "Contains()" basicamente faz isso, um "foreach" e cada objeto rodando o método "Equals()" dele.

    //Código do Contains (veja o link que pus anteriomente)
    public virtual bool Contains(Object item)
    {
        if (item==null)
        {
            for (int i = 0; i < _size; i++)
                if (_items[i]==null) return true;
            return false;
        }
        else
        {
            for(int i=0; i<_size; i++)
                if ((_items[i] != null) && (_items[i].Equals(item))) return true;
            return false;
        }
    }
    
    //Seu "foreach"
    public bool Contains(List<Info> Produtos, Info Item)
    {
        if (Item == null)
        {
            //Faça o mesmo? Ou não pode ser null nunca ...
            //Ai você decide
        }
        foreach (Info Existing in Produtos)
            if (Existing.Nome == Item.Nome && Existing.Valor == Existing.Valor) return true;
        //Era para comparar o valor também ou só o nome?
        return false;
    }

    Entendeu o exemplo?

    • Sugerido como Resposta SammuelMiranda segunda-feira, 20 de junho de 2016 12:14
    • Marcado como Resposta Thales F Quintas segunda-feira, 20 de junho de 2016 13:39
    segunda-feira, 20 de junho de 2016 12:14
  • Entendi muito bem a parte do contains que ele retorna verdadeiro ou falso. A parte verificar algum item já adicionado eu não entendi como fazer :/
    segunda-feira, 20 de junho de 2016 12:21
  • Verificar os itens já adicionados na list para não pode adicionar dois do mesmo. Preciso apenas só verificar o nome, o valor não me interessa. Hehe
    segunda-feira, 20 de junho de 2016 12:22
  • Então substitua isso:

    public bool Contains(List<Info> Produtos, Info Item)
    {
        if (Item == null)
        {
            //Faça o mesmo? Ou não pode ser null nunca ...
            //Ai você decide
        }
        foreach (Info Existing in Produtos)
            if (Existing.Nome == Item.Nome && Existing.Valor == Existing.Valor) return true;
        //Era para comparar o valor também ou só o nome?
        return false;
    }

    Por isso:

    public bool Contains(List<Info> Produtos, Info Item)
    {
        foreach (Info Existing in Produtos)
            if (Existing.Nome == Item.Nome) return true;
        return false;
    }

    A parte do "Item == null" é para você tratar se o item for nulo o que fazer.

    segunda-feira, 20 de junho de 2016 19:33