Итак, сегодня я столкнулся со странной проблемой - у меня было простое создание экземпляра внутри критической секции блокировки, и оно выдавало исключение нулевой ссылки, когда я вручную перетаскивал следующую строку для выполнения. Для иллюстрации:
public class SearchEngineOptimizationParser
{
protected static ConcurrentDictionary<string, SearchEngineOptimizationInfo> _referralInformation = null;
protected static DateTime _lastRecordingDate;
protected static object _lockRecordingObject = new object();
protected static Dictionary<string, string> _searchProviderLookups = null;
static SearchEngineOptimizationParser()
{
_referralInformation = new ConcurrentDictionary<string, SearchEngineOptimizationInfo>();
_lastRecordingDate = DateTime.Now;
_searchProviderLookups = new Dictionary<string, string>();
_searchProviderLookups.Add("google.com", "q");
_searchProviderLookups.Add("yahoo.com", "p");
_searchProviderLookups.Add("bing.com", "q");
}
public SearchEngineOptimizationParser()
{
}
public virtual void ParseReferrer(Uri requestUrl, NameValueCollection serverVariables, ISession session)
{
string corePath = requestUrl.PathAndQuery.SmartSplit('?')[0].ToLower();
string referrer = serverVariables["HTTP_REFERER"];
if (!string.IsNullOrWhiteSpace(referrer))
{
NameValueCollection queryString = HttpUtility.ParseQueryString(referrer);
string dictionaryKey = session.AffiliateID + "|" + corePath;
foreach (var searchProvider in _searchProviderLookups)
{
if (referrer.Contains(searchProvider.Key))
{
if (queryString[searchProvider.Value] != null)
{
string keywords = queryString[searchProvider.Value];
SearchEngineOptimizationInfo info = new SearchEngineOptimizationInfo
{
Count = 1,
CorePath = corePath,
AffiliateId = session.AffiliateID,
Keywords = keywords
};
_referralInformation.AddOrUpdate(dictionaryKey, info, (key, oldValue) =>
{
oldValue.Count++;
return oldValue;
});
break;
}
}
}
}
if (DateTime.Now > _lastRecordingDate.AddHours(1))
{
lock (_lockRecordingObject)
{
if (DateTime.Now > _lastRecordingDate.AddHours(1))
{
SearchEngineKeywordRepository repository = new SearchEngineKeywordRepository();
List<KeyValuePair<string, SearchEngineOptimizationInfo>> currentInfo = _referralInformation.ToList();
Action logData = () =>
{
foreach (var item in currentInfo)
repository.LogKeyword(item.Value);
};
Thread logThread = new Thread(new ThreadStart(logData));
logThread.Start();
_lastRecordingDate = DateTime.Now;
_referralInformation.Clear();
}
}
}
}
РЕДАКТИРОВАТЬ: Обновлен реальный объект
public class SearchEngineKeywordRepository
{
public virtual void LogKeyword(SearchEngineOptimizationInfo keywordInfo)
{
LogSearchEngineKeywords procedure = new LogSearchEngineKeywords();
procedure.Execute(keywordInfo.CorePath, keywordInfo.AffiliateId, keywordInfo.Keywords, keywordInfo.Count);
}
}
В целом, я хочу делать это «что-то» только каждый час (в контексте веб-приложения, которое получает много трафика). Я бы остановил свой первый оператор if, а затем перешел к следующей строке для выполнения внутри второго оператора if. При этом инициализация экземпляра SomeObject
вызовет исключение нулевой ссылки. У него был полностью 100% конструктор по умолчанию - я даже не указал его.
Однако, когда я позволю коду пройти естественным образом, он будет выполняться без проблем. По какой-то причине кажется, что когда я пропустил вызов блокировки в критическую секцию, чтобы просто протестировать выполнение этого кода, это вызвало все виды ошибок.
Мне любопытно узнать, почему это так; Я понимаю, что ключевое слово lock
является просто синтаксическим сахаром для блока Monitor.Enter(o)
try / finally, но похоже, что при вызове конструктора происходило что-то еще.
У кого-нибудь есть идеи?
РЕДАКТИРОВАТЬ: я добавил фактический код к этому. Я могу воспроизвести это по своему желанию, но я все еще не понимаю, почему это происходит. Я попытался скопировать этот код в другое решение, и проблема, похоже, не возникает.