List <t>获取正在执行的块号</t>

时间:2012-10-25 01:06:30

标签: c# linq

我将列表分成块并按如下方式处理:

foreach (var partialist in breaklistinchunks(chunksize))
{
  try
   {
       do something
  }
catch
{
print error
}

}



public static class IEnumerableExtensions
    {
        public static IEnumerable<List<T>> BreakListinChunks<T>(this IEnumerable<T> sourceList, int chunkSize)
        {
            List<T> chunkReturn = new List<T>(chunkSize);
            foreach (var item in sourceList)
            {
                chunkReturn.Add(item);
                if (chunkReturn.Count == chunkSize)
                {
                    yield return chunkReturn;
                    chunkReturn = new List<T>(chunkSize);
                }
            }
            if (chunkReturn.Any())
            {
                yield return chunkReturn;
            }
        }
    }

如果出现错误,我希望再次运行该块。是否有可能找到我们收到错误的特定块号并再次运行? 批次必须按顺序执行。因此,如果批次#2生成错误,那么我需要能够再次运行2,如果它再次失败。我只需要好好摆脱循环。

5 个答案:

答案 0 :(得分:4)

List<Chunk> failedChunks = new List<Chunk>();
foreach (var partialist in breaklistinchunks(chunksize))
{
    try
    {
        //do something
    }
    catch
    {
        //print error
        failedChunks.Add(partiallist);
    }

}

// attempt to re-process failed chunks here

答案 1 :(得分:2)

我根据your commentAaron's answer提出此答案。

  

批次必须按顺序执行。如果2是个问题,那么我需要能够再次运行2,如果它再次失败。我只需要好好摆脱循环。

foreach (var partialist in breaklistinchunks(chunksize))
{
    int fails = 0;
    bool success = false;

    do
    {
        try
        {
            // do your action
            success = true; // should be on the last line before the 'catch'
        }
        catch
        {
            fails += 1;
            // do something about error before running again
        }
    }while (!success && fails < 2);

    // exit the iteration if not successful and fails is 2
    if (!success && fails >= 2)
        break;
}

答案 2 :(得分:1)

如果您不介意从Enumerable切换到Queue,我为您提供了一个可能的解决方案,这种方式符合要求......

void Main()
{
    var list = new Queue<int>();
    list.Enqueue(1);
    list.Enqueue(2);
    list.Enqueue(3);
    list.Enqueue(4);
    list.Enqueue(5);

    var random = new Random();

    int chunksize = 2;
    foreach (var chunk in list.BreakListinChunks(chunksize))
    {
        foreach (var item in chunk)
        {   
            try
            {           
                if(random.Next(0, 3) == 0) // 1 in 3 chance of error
                    throw new Exception(item + " is a problem");
                else
                    Console.WriteLine (item + " is OK");
            }
            catch (Exception ex)
            {
                Console.WriteLine (ex.Message);
                list.Enqueue(item);
            }
        }
    }
}

public static class IEnumerableExtensions
{   
    public static IEnumerable<List<T>> BreakListinChunks<T>(this Queue<T> sourceList, int chunkSize)
    {
        List<T> chunkReturn = new List<T>(chunkSize);
        while(sourceList.Count > 0)
        {
            chunkReturn.Add(sourceList.Dequeue());
            if (chunkReturn.Count == chunkSize || sourceList.Count == 0)
            {
                yield return chunkReturn;
                chunkReturn = new List<T>(chunkSize);
            }       
        }
    }
}

输出

1 is a problem
2 is OK
3 is a problem
4 is a problem
5 is a problem
1 is a problem
3 is OK
4 is OK
5 is OK
1 is a problem
1 is OK

答案 3 :(得分:0)

一种可能性是使用for循环而不是foreach循环,并使用计数器作为确定错误发生位置的方法。然后你可以从你离开的地方继续。

答案 4 :(得分:0)

一旦块失败两次,您就可以使用break退出循环:

foreach (var partialList in breaklistinchunks(chunksize))
{
    if(!TryOperation(partialList) && !TryOperation(partialList))
    {
        break;
    }
}

private bool TryOperation<T>(List<T> list)
{
    try
    {
        // do something
    }
    catch
    {
        // print error
        return false;
    }
    return true;
}

你甚至可以使用LINQ将循环变成单行,但将LINQ与副作用结合起来通常是不好的做法,而且它的可读性不高:

breaklistinchunks(chunksize).TakeWhile(x => TryOperation(x) || TryOperation(x));