小弟最近面试遇到一个题目,一个关于客户旅行行程的类,有一些操作,包括一些异步操作。
要求找出其中写的不好的地方,并提出改进方案
根据好的编码标准和设计,检查以下代码,这是部分实现的一个行程计划。指出您可以在代码中看到的任何问题(如果有的话),以及应该做些什么来改进它们。
/// <summary>
/// Provides capabilities for managing a customers itinerary.
/// </summary>
public class ItineraryManager
{
private readonly IDataStore _dataStore;
private readonly IDistanceCalculator _distanceCalculator;
public ItineraryManager()
{
_dataStore = new SqlAgentStore(ConfigurationManager.ConnectionStrings["SqlDbConnection"].ConnectionString);
_distanceCalculator = new GoogleMapsDistanceCalculator(ConfigurationManager.AppSettings["GoogleMapsApiKey"]);
}
/// <summary>
/// Calculates a quote for a customers itinerary from a provided list of airline providers.
/// </summary>
/// <param name="itineraryId">The identifier of the itinerary</param>
/// <param name="priceProviders">A collection of airline price providers.</param>
/// <returns>A collection of quotes from the different airlines.</returns>
public IEnumerable<Quote> CalculateAirlinePrices(int itineraryId, IEnumerable<IAirlinePriceProvider> priceProviders)
{
var itinerary = _dataStore.GetItinaryAsync(itineraryId).Result;
if (itinerary == null)
throw new InvalidOperationException();
List<Quote> results = new List<Quote>();
Parallel.ForEach(priceProviders, provider =>
{
var quotes = provider.GetQuotes(itinerary.TicketClass, itinerary.Waypoints);
foreach (var quote in quotes)
results.Add(quote);
});
return results;
}
/// <summary>
/// Calculates the total distance traveled across all waypoints in a customers itinerary.
/// </summary>
/// <param name="itineraryId">The identifier of the itinerary</param>
/// <returns>The total distance traveled.</returns>
public async Task<double> CalculateTotalTravelDistanceAsync(int itineraryId)
{
var itinerary = await _dataStore.GetItinaryAsync(itineraryId);
if (itinerary == null)
throw new InvalidOperationException();
double result = 0;
for(int i=0; i<itinerary.Waypoints.Count-1; i++)
{
result = result + _distanceCalculator.GetDistanceAsync(itinerary.Waypoints[i],
itinerary.Waypoints[i + 1]).Result;
}
return result;
}
/// <summary>
/// Loads a Travel agents details from Storage
/// </summary>
/// <param name="id">The id of the travel agent.</param>
/// <param name="updatedPhoneNumber">If set updates the agents phone number.</param>
/// <returns>The travel agent if located, otherwise null.</returns>
public TravelAgent FindAgent(int id, string updatedPhoneNumber)
{
var agentDao = _dataStore.GetAgent(id);
if (agentDao == null)
return null;
if (!string.IsNullOrWhiteSpace(updatedPhoneNumber))
{
agentDao.PhoneNumber = updatedPhoneNumber;
_dataStore.UpdateAgent(id, agentDao);
}
return Mapper.Map<TravelAgent>(agentDao);
}
}
List<Quote> results = new List<Quote>();
Parallel.ForEach(priceProviders, provider =>
{
var quotes = provider.GetQuotes(itinerary.TicketClass, itinerary.Waypoints);
foreach (var quote in quotes)
results.Add(quote);
});
return results;
Parallel.ForEach我记得没错会执行多线程,但是直线的线程都共用同一个实例results ,这样可能会导致results 有重复数据
你好,在线等大神解答
先说一个呗
并行计算下的线程安全
什么意思
这个代码有问题么
有线程安全的问题么
Parallel.ForEach(priceProviders, provider =>
{
var quotes = provider.GetQuotes(itinerary.TicketClass, itinerary.Waypoints);
foreach (var quote in quotes)
results.Add(quote);
});
@新西兰程序员: 最后results里的数据可能会比正常的少。比如在resuls内对象数量为5时被两个线程同时获取到然后插入一条记录,最终得到的就会是数量为6 而不是7
@孤月星霜:
那是不是说,我就用C#中普通的foreach循环就可以,在这里
而不要用Parallel.ForEach
对么
@新西兰程序员: 循环是一种;还有一种是用 ParallelQuery 替换 Parallel
比如:priceProviders.AsParallel()
具体用哪一种看你循环是否耗时了
@孤月星霜:
不知道啊,这就是一道笔试题,所有代码都在这里
我按照你的建议,改成了foreach 提交上去了
@新西兰程序员: 这还可以隔好几天之后再提交的呀....
@新西兰程序员: 那这个代码还有好几处需要修改的 哈哈 你仔细找找
@孤月星霜:
能够帮我指出来一下么
我也找了一些
就怕漏掉了