Странная ситуация с полем блокировки, равным нулю - С#, вероятно, специфично для .net 4.0 win8-32

У меня есть следующий код:

public class Settings
{
    private object _lock = new object();
    public void Save() {
        lock (_lock)
        {
        ...
        }
    }
}

В Windows 8 x86/.net 4.0 блокировка выдает исключение:

Exception Type:        System.ArgumentNullException
Exception Message:     Value cannot be null.
Exception Target Site: ReliableEnter 

Я подключил отладчик и его ноль. _lock действительно нулевой :|

На виндовс 7 х64 работает нормально. Сейчас проверяю другие ОС.

РЕДАКТИРОВАТЬ:

Это связано с десериализацией. После десериализации класса Settings _lock имеет значение null. Поле _lock не существовало во время сериализации настроек и его обратное десериализация как нуль. Удаление сериализованного объектного файла и его воссоздание с устранением исключения поля блокировки. Я проверю, правильно ли это поведение десериализации, если поле не существует при сериализации. Перезапись значения объекта, инициализированного в объявлении, мне не кажется крутым. Но это в значительной степени ответ на это. Я признаю, что я не рассматривал сериализацию, десериализацию в то время, когда я обратился за помощью;).

EDIT2: Вот код, иллюстрирующий мой сценарий и то, что со мной происходило:

  1. Сериализация класса без поля _lock

    class Program
    {
        static void Main(string[] args)
        {
            Settings set = new Settings();
    
            using (FileStream fs = new FileStream(@"C:\test\tst.set", FileMode.Create, FileAccess.Write, FileShare.None))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(fs, set);
                fs.Flush();
                fs.Close();
            }
        }
    }
    
    [Serializable]
    internal class Settings
    {
        private int _i = 12;
    
    
        public void testMethod()
        {
    
            int i = 0;
            i++;
            Console.WriteLine(i);
    
        }
    }
    
  2. Десериализовать в класс с полем блокировки и вызвать testMethod:

    class Program
    {
        static void Main(string[] args)
        {
            Settings set = null;
            using (FileStream fs = new FileStream(@"C:\test\tst.set", FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                BinaryFormatter bf = new BinaryFormatter();
                set = (Settings)bf.Deserialize(fs);
                fs.Flush();
                fs.Close();
            }
    
            set.testMethod();
        }
    }
    
    [Serializable]
    internal class Settings
    {
        private int _i = 12;
        private readonly object _lock = new object();
    
        public void testMethod()
        {
            lock (_lock)
            {
                int i = 0;
                i++;
                Console.WriteLine(i);
            }
        }
    }
    

программа рухнет при вызове testMethod.

Я не нашел ничего, связанного с этим поведением в документации. Я проверю значение null после десериализации, и это положит конец моей проблеме.

В порядке. Как десериализация может присвоить значение null моему полю только для чтения, назначенному при объявлении?


person Velja Radenkovic    schedule 16.03.2015    source источник
comment
Предоставьте короткую, но полную программу, демонстрирующую проблему.   -  person Jon Skeet    schedule 16.03.2015
comment
Первое, что нужно проверить, где вы переназначаете _lock на ноль? Отметьте поле как readonly. Компилятор будет кричать на вас, если вы это сделаете. Если нет, предоставьте короткую, но полную программу, как просит @JonSkeet.   -  person Sriram Sakthivel    schedule 16.03.2015
comment
Это то, на что у меня есть время в данный момент. Запись экрана: screencast.com/t/xiU73MrSy Я постараюсь собрать минимальный кейс, как только получу когда-то.   -  person Velja Radenkovic    schedule 16.03.2015
comment
Выполняется только для чтения. Изначально он был доступен только для чтения. Никаких других ссылок на _lock.   -  person Velja Radenkovic    schedule 16.03.2015
comment
М-м-м. Экземпляр объекта, который ведет себя, создается путем десериализации. Позвольте мне попытаться построить что-то, что воспроизводится.   -  person Velja Radenkovic    schedule 16.03.2015
comment
Минимальный тестовый пример выше, поэтому это решение моей проблемы. Спасибо, ребята, и извините, что потратил ваше время на неполный вопрос. Причина, по которой он не работал на win 7 / x64, заключалась в том, что у него не было старых настроек / сериализованного файла.   -  person Velja Radenkovic    schedule 16.03.2015
comment
В ПОРЯДКЕ. Я снова поднимаю этот вопрос. Пожалуйста, просмотрите отредактированный вопрос и особенно последнюю строку.   -  person Velja Radenkovic    schedule 16.03.2015


Ответы (2)


Во всех смыслах и целях, если вы установите его на новый объект и больше нигде не измените, то то, что вы видите, невозможно.

Первое, что я бы попробовал, это переместить новый код объекта в мой конструктор, если он там устраивает, то оставить его в покое. В любом случае, проследите за назначением и посмотрите, было ли оно когда-либо назначено.

Убедитесь, что ваша IDE не отслеживает ничего, что могло бы повлиять на значение переменной как побочный эффект - проверьте условные точки останова на предмет того же.

Обратите внимание, что вы можете создать условную точку останова при изменении!

Если все еще не работает добавление утверждений, скомпилируйте в режиме отладки - запустите вне среды IDE.

Если отладочная версия дает сбой, когда IDE не является частью микса, перенесите ее на другие ПК и попробуйте.

Если это работает на других ПК, сканирование на вирусы / переустановка и т. д. Проверка памяти и т. д.

Возможно, компилятор не работает, попробуйте переустановить Visual Studio.

Тогда у меня нет идей!

person Mark Rabjohn    schedule 16.03.2015
comment
Буду признателен, если вы посмотрите на мой отредактированный вопрос. Особенно последнее редактирование и последние строки. - person Velja Radenkovic; 16.03.2015
comment
Единственное, что я могу придумать, это использовать атрибут [NotSerialized] для _lock. - person Mark Rabjohn; 18.03.2015
comment
Это не работает. Устанавливает его в значение null с несерилизованным атрибутом и вылетает с той же ошибкой. Вы можете попробовать только последние изолированные случаи с атрибутом NonSerializable. Они готовы к компиляции. До этого экземпляра я думал так: поскольку вам нужно предоставить пустой конструктор (или оставить без него, поэтому компилятор создает один пустой), чтобы класс был сериализуемым, я думал, что десериализация создает экземпляр класса, создавая его, и после этого он устанавливает свои поля к сериализованным значениям. У меня сложилось впечатление, что это не должно делать это для полей только для чтения. Но сейчас я понятия не имею. - person Velja Radenkovic; 18.03.2015
comment
Кстати, это необязательный технический разговор сейчас. Я решил свою проблему, как только понял, что происходит, установив блокировку на новый объект () после десериализации. - person Velja Radenkovic; 18.03.2015

Частные свойства по умолчанию не сериализуются. Если вы хотите, чтобы они были сериализованы, вам нужно создать собственные методы сериализатора.

Дополнительные сведения можно найти в следующем вопросе.

person Juan    schedule 16.03.2015
comment
Нет, я не хочу, чтобы они были сериализованы. Есть ли кто-нибудь, кто хотел бы сериализовать блокировку? его поле только для чтения. Как десериализация устанавливает его в нуль? Или как при десериализации ему не назначается назначение объявления. частный объект только для чтения _lock = новый объект(); - person Velja Radenkovic; 16.03.2015
comment
Если вы не хотите быть сериализованным, считайте, что он перемещен за пределы класса. Или добавьте настраиваемую логику десериализации, чтобы воссоздать ее (и удалите бит только для чтения: (). Этот вопрос может добавить к этому больше деталей: stackoverflow.com/questions/9328720/ - person Juan; 16.03.2015