Proč úpravou kolekce také upravuje předchozí v foreach

0

Otázka

V podstatě účely můj kód je následující: Mám sbírku agentů, "Matricule" a "Temps Základnu". Někteří agenti mají pouze jeden "Temps Základnu", a oni budou jen jednou v kolekci, ale jiní mají více než jeden "Temps Základnu", a proto se objeví několikrát. Pokud agent má pouze jeden "Temps Base" (zastoupen dvakrát), žádný problém. Pokud má více než jeden, například tři, jen se chci přidat, vedení pouze jeden objekt, ale který obsahuje součet tří čtyřhře.

Tady je moje třída:

public class AgentJournalier
{
    public string Matricule { get; set; }
    public double TempsBase{ get; set; }
}

Mé sbírky :

    private ObservableCollection<AgentModel> _TousAgents;
    public ObservableCollection<AgentModel> TousAgents
    {
        get
        {
            return _TousAgents;
        }
        set
        {
            if (value != _TousAgents)
            {
                _TousAgents = value;
                RaisePropertyChanged(nameof(TousAgents));
            }
        }
    }

    private ObservableCollection<AgentModel> _AgentsContratEnCours;
    public ObservableCollection<AgentModel> AgentsContratEnCours
    {
        get
        {
            return _AgentsContratEnCours;
        }
        set
        {
            if (value != _AgentsContratEnCours)
            {
                _AgentsContratEnCours = value;
                RaisePropertyChanged(nameof(AgentsContratEnCours));
            }
        }
    }

Pro tento test, moje Sbírka TousAgents bude obsahovat 3 řádky :

Matricule : Bec  -  TempsBase : 100
Matricule : Bec  -  TempsBase : -25
Matricule : Bec  -  TempsBase : -10

Můj kód :

        foreach (AgentModel tsag in TousAgents)
        {
            if (AgentsContratEnCours.Any(p => p.Matricule == tsag.Matricule) == false)
            {
               AgentsContratEnCours.Add(tsag);
            }
            else
            {
               AgentModel AgentDejaDansLaListe = new AgentModel();
               AgentDejaDansLaListe = AgentsContratEnCours.Where(x => x.Matricule == tsag.Matricule).FirstOrDefault();

               AgentsContratEnCours.Remove(AgentsContratEnCours.Where(x => x.Matricule == tsag.Matricule).FirstOrDefault());

               AgentDejaDansLaListe.TempsBase = AgentDejaDansLaListe.TempsBase + tsag.TempsBase;

               AgentsContratEnCours.Add(AgentDejaDansLaListe);                
            }
        }

        foreach (AgentModel tsag in TousAgents)
        {
            Console.WriteLine($"Temps base : {tsag.TempsBase}");
        }

        foreach (AgentModel tsag in AgentsContratEnCours)
        {
            Console.WriteLine($"Temps base total : {tsag.TempsBase}");
        }

Vzhledem agenta, který by byl třikrát v seznamu se stejným "Matricule", ale s 3 různých "TempsBase" (ex : 100, -10, -25), výstup rád bych je následující:

Output :
Temps base : 100
Temps base : -25
Temps base : -10
Temps base total : 65

Ale na výstupu vlastně je to jeden:

Output :
Temps base : 65 <== Why ??
Temps base : -25
Temps base : -10
Temps base total : 65

Samozřejmě, když budu volat metodu podruhé, "Temps Základnu," pokračuje decrement (protože to již nemá původní hodnotu, 100, ale nové: 65):

Output :
Temps base : 30 <== Why ??
Temps base : -25
Temps base : -10
Temps base total : 30

Chtěl bych pochopit, proč tato první hodnota v "TousAgents" změny. Mým cílem je, že hodnoty v první Kolekci se nikdy nezmění, a tak jsem vytvořit druhý : AgentsContratEnCours. Ale když jsem změnit hodnoty v AgentsContratEnCours, ale také změny v TousAgents i když já neposílám nic ručně "TousAgents". Můžete mi vysvětlit, proč ? A jak se mohu vyhnout?

c# mvvm observablecollection
2021-11-23 09:24:59
1

Nejlepší odpověď

4

Problematické předpokladu, že jste provedli, pokud jde referenční typy vás vedlo k tomuto omylu. Falešný předpoklad, je v následujícím kódu, poznáte to?

AgentModel AgentDejaDansLaListe = new AgentModel();
AgentDejaDansLaListe = AgentsContratEnCours.Where(x => x.Matricule == tsag.Matricule).FirstOrDefault();

AgentDejaDansLaListe.TempsBase = AgentDejaDansLaListe.TempsBase + tsag.TempsBase;

Nech mě to vysvětlit. AgentModel je referenční typ, to znamená, že pokud budete měnit jeho vlastnosti (Marticule a TempsBase) v AgentModel budou se měnit ve všech kopiích.

V první řadě si vytvořit nový AgentModel jménem AgentDejaDansLaListe pak se na druhém řádku se vám hodit to pryč (garbage collector) a pak přiřadit zcela jiný odkaz na něj.

V posledním řádku upravit TempsBase, že objekt, který se také mění TempsBase, že původní objekt v seznamu, protože AgentModel je referenční typ.


Chcete-li opravit, buď použít struct pro AgentModel nebo provedení Klon.

2021-11-23 09:37:42

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................