На нашем веб-сайте есть страница конфигурации, такая как "config.aspx", когда инициализация страницы загрузит некоторую информацию из файла конфигурации. Чтобы кэшировать загруженную информацию, мы предоставили класс factory, и мы вызываем общедоступный метод factory, чтобы получить экземпляр конфигурации при загрузке страницы. Но иногда, когда пул приложений перезагружается, мы обнаружили сообщение об ошибке в журнале событий, например:
Message: Object reference not set to an instance of an object. Stack: at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value) at ObjectFactory.GetInstance(string key) at config.Page_Load(Object sender, EventArgs e) at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Класс factory реализует, как показано ниже:
public static class ObjectFactory
{
private static object _InternalSyncObject;
private static Dictionary _Instances;
private static object InternalSyncObject
{
get
{
if (_InternalSyncObject == null)
{
var @object = new object();
Interlocked.CompareExchange(ref _InternalSyncObject, @object, null);
}
return _InternalSyncObject;
}
}
private static Dictionary Instances
{
get
{
if (_Instances == null)
{
lock (InternalSyncObject)
{
if (_Instances == null)
{
_Instances = new Dictionary();
}
}
}
return _Instances;
}
}
private static object LoadInstance(string key)
{
object obj = null;
// some statements to load an specific instance from a configuration file.
return obj;
}
public static object GetInstance(string key)
{
object instance;
if (false == Instances.TryGetValue(key, out instance))
{
instance = LoadInstance(key);
Instances[key] = instance;
}
return instance;
}
}
Я предполагаю, что исключение было выбрано строкой "Экземпляры [ключ] = экземпляр", потому что это единственный код, который мог бы вызвать метод set_Item
словаря. Но если значение "Экземпляры" равно NULL, при вызове метода TryGetValue
будет выбрано значение NullReferenceException
, а верхний фрейм stacktrace должен быть GetInstance
, а не Insert
. Кто-нибудь знает, как словарь может выбросить NullReferenceException
при вызове метода set_Item
в многопоточном сценарии?