Search code examples
c#linqparallel.foreach

LINQ Order by - Parallel.Foreach


I have a very strange problem with LINQ "order by" and Parallel.Foreach

Specifically, this code works:

IList<IEntitaAssociabile> result = new List<IEntitaAssociabile>();

foreach(PraticheAperteNonAssegnate pratica in praticheAperteNonAssegnate)
{
    result.Add(new EntitaAssociabile
    {
          Id = pratica.ID_Prat,
          TipologiaEntita = TipologiaEntita.Pratica,
          DataApertura = pratica.DataAper.Value,
          TipologiaPratica = pratica.Cod_TpPrat,
          NomeCliente = pratica.Nominativo,
          NumeroPraticheDaAssociare = null,
          TipologiaEntitaPadre = GetEntitaPadre(pratica, praticheLotti, praticheSottolotti),
          IdEntitaPadre = GetIdEntitaPadre(pratica, praticheLotti, praticheSottolotti)
    });
}

return result.OrderBy(x => x.Id).ToList();

If I simply change foreach statement with Parallel.Foreach:

 IList<IEntitaAssociabile> result = new List<IEntitaAssociabile>();

 Parallel.ForEach(praticheAperteNonAssegnate, (pratica) =>
 {
      result.Add(new EntitaAssociabile
      {
           Id = pratica.ID_Prat,
           TipologiaEntita = TipologiaEntita.Pratica,
           DataApertura = pratica.DataAper.Value,
           TipologiaPratica = pratica.Cod_TpPrat,
           NomeCliente = pratica.Nominativo,
           NumeroPraticheDaAssociare = null,
           TipologiaEntitaPadre = GetEntitaPadre(pratica, praticheLotti, praticheSottolotti),
           IdEntitaPadre = GetIdEntitaPadre(pratica, praticheLotti, praticheSottolotti)
      });
  });

  return result.OrderBy(x => x.Id).ToList();

On the "order by" I have a "Null object reference exception"

I can't understand why with foreach the code works but not with Parallel.Foreach.

Can you help me and explain what's the problem?


Solution

  • Well, List<T> is not thread safe, that's why adding to result within Parallel.ForEach leads to problems. If you insist on parallel execution, try PLinq (Parallel Linq) instead:

    IList<IEntitaAssociabile> result = praticheAperteNonAssegnate
      .AsParallel()
      .Select(pratica => new EntitaAssociabile() {
         Id = pratica.ID_Prat,
         ...
       })
      .OrderBy(item => item.Id)
      .ToList();
    

    Comment out .AsParallel() if you want to switch to good old Linq.