当断点似乎神奇地出现在枚举器内的同一位置两次时,我只是花了一些时间挠头。
事实证明,这个错误是一个直接的疏忽:
protected override void Extract()
{
LogGettingOffers();
var offerIds = CakeMarketingUtility.OfferIds(advertiserId);
LogExtractingClicks(offerIds);
foreach (var offerId in offerIds)
{
int rowCount;
var clicks = RetryUtility.Retry(3, 10000, new[] { typeof(Exception) }, () =>
{
return CakeMarketingUtility.EnumerateClicks(dateRange, advertiserId, offerId);
});
foreach (var clickBatch in clicks.InBatches(1000))
{
LogExtractedClicks(offerId, clickBatch);
// SHOULD BE clickBatch, NOT clicks
Add(clicks);
}
}
End();
}
这让我想知道一个人可能会采取什么(如果有的话)预防措施来编写捕获这样的错误的代码。
请注意,我并不肯定沿着这条思路走下去是有意义的——也许答案是“不要编写不正确的代码”,我愿意接受。
这是产生结果的实际代码:
public static IEnumerable<Click> EnumerateClicks(DateRange dateRange, int advertiserId, int offerId)
{
// initialize to start at the first row
int startAtRow = 1;
// hard code an upper limit for the max number of rows to be returned in one call
int rowLimitForOneCall = 5000;
bool done = false;
int total = 0;
while (!done)
{
Logger.Info("Extracted a total of {0} rows, checking for more, starting at row {1}..", total, startAtRow);
// prepare the request
var request = new ClicksRequest
{
start_date = dateRange.FromDate.ToString("MM/dd/yyyy"),
end_date = dateRange.ToDate.ToString("MM/dd/yyyy"),
advertiser_id = advertiserId,
offer_id = offerId,
row_limit = rowLimitForOneCall,
start_at_row = startAtRow
};
// create the client, call the service and check the response
var client = new ClicksClient();
var response = client.Clicks(request);
if (!response.Success)
{
throw new Exception("ClicksClient failed");
}
// update the running total
total += response.RowCount;
// return result
foreach (var click in response.Clicks)
yield return click;
// update stopping condition for loop
done = (response.RowCount < rowLimitForOneCall);
// increment start row for next iteration
startAtRow += rowLimitForOneCall;
}
Logger.Info("Extracted a total of {0}, done.", total);
}