Может поле только для чтения в.NET становиться пустым?

Google не рассматривал подчеркивание как разделителя слов в прошлом, который я думал, было довольно сумасшедшим, но по-видимому это делает теперь. Из-за этой истории предпочтены тире. Даже при том, что подчеркивания теперь допустимы с точки зрения SEO, я все еще думаю, что тире являются лучшими.

Одно преимущество - то, что Ваше среднее число semi-computer-illiterate веб-пользователь, намного более вероятно, будет в состоянии ввести тире на клавиатуре, они даже не могут знать, каково подчеркивание.

6
задан Radu094 7 December 2009 в 22:30
поделиться

9 ответов

Отражение - один из способов сделать это ( SetField ).

Второй способ вызвать это любопытство - это если вы дадите ссылку слишком рано, передав this (или что-то, включающее неявное this , например, поле, захваченное анонимным методом / лямбда) из .ctor :

public MyClass(int id)
{
    Program.Test(this); // oopsie ;-p
    HashPrefs = new Hashtable();
}

Или более вероятно (учитывая вопрос):

SomeQueue.Add(this);

Другой уместный вопрос - нельзя ли его вообще назначить? И ответ на это - да, особенно если вы используете сериализацию. Вопреки распространенному мнению, вы действительно можете обойти конструкторы, если у вас есть причина; DataContractSerializer - хороший пример того, что делает это ...

Следующее создаст MyClass с пустым полем:

MyClass obj = (MyClass)
    System.Runtime.Serialization.FormatterServices.GetUninitializedObject(
        typeof(MyClass));
11
ответ дан 8 December 2019 в 03:53
поделиться

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

Однако есть много других вещей, которые также могут создавать для вас проблемы. Многопоточный код сложно написать, и проблемы, которые могут возникнуть, трудно диагностировать.


В качестве примечания: вы уверены, что не получаете ArgumentNullException ? Если somekey равно null , метод Hashtable.Contains вызовет исключение ArgumentNullException . Может, в этом проблема?

7
ответ дан 8 December 2019 в 03:53
поделиться

Ваши инструкции могут быть переупорядочены так, чтобы ссылка на экземпляр MyClass добавлялась в очередь до того, как она будет полностью построена. Вот статья о блокировке с двойной проверкой, которая как бы затрагивает эту тему. Из статьи:

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

Взгляните на System.Threading.Thread.MemoryBarrier. Возможно, вам потребуется сделать что-то вроде этого:

 MyClass temp = new MyClass(1);
 System.Threading.Thread.MemoryBarrier();
 SomeQueue.Add(temp);

MemoryBarrier гарантирует, что все инструкции перед ним будут выполнены перед продолжением.

3
ответ дан 8 December 2019 в 03:53
поделиться

Прежде всего, другой поток не может получить доступ к экземпляру, пока конструктор не будет завершен, поскольку сам экземпляр не будет назначен, пока конструктор не будет завершен. При этом другой поток может получить доступ к переменной , содержащей экземпляр, до завершения работы конструктора, но в то время он будет null . Это сгенерирует NullReferenceException , но оно будет исходить из метода, обращающегося к экземпляру, а не из метода внутри экземпляра.

Все сказанное, единственное реальное решение что я вижу, это использование внешней блокировки, которая синхронизирует код при извлечении экземпляра. Если вы обращаетесь к Hashset (или к любому другому типу, в котором член экземпляра не указан) t гарантированно является потокобезопасным), вам в любом случае необходимо выполнить блокировку операций.

Считайте следующий класс тем, который содержит ссылку на MyClass и создателя других потоков:

public class MasterClass
{
    private MyClass myClass;
    private object syncRoot = new object(); // this is what we'll use to synchronize the code

    public void Thread1Proc()
    {
        lock(syncRoot)
        {
            myClass = new MyClass();
        }
    }

    public void Thread2Proc()
    {
        lock(syncRoot)
        {
            myClas.SomeMethodCalledFromAnotherThread();
        }
    }
}

] Это очень (возможно, чрезмерно) упрощенное представление о том, как должна происходить синхронизация, но общая идея этого подхода заключается в том, чтобы обернуть весь код, который взаимодействует с разделяемым объектом, внутри блока lock . Вы действительно должны изучить, как писать многопоточные процессы, и различные подходы, направленные на совместное использование ресурсов между несколькими потоками.

EDIT

Совершенно другая возможность состоит в том, что значения переменной экземпляра кэшируются в потоке специфическим образом. Если вы не блокируете (что создает барьер памяти),

3
ответ дан 8 December 2019 в 03:53
поделиться

Вы уверены, что исключение выдает именно HashPrefs.Contains, а не то, что представляет собой somekey? Если нет, не могли бы вы опубликовать полную информацию об исключении, возвращенную его методом ToString?

1
ответ дан 8 December 2019 в 03:53
поделиться

Просто выполните

HashPrefs = Hashtable.Synchronized(new Hashtable());

Нет необходимости изобретать велосипед.

1
ответ дан 8 December 2019 в 03:53
поделиться

Вы абсолютно уверены, что HashPrefs.Contains бросает NPE? Я бы подумал, что SomeQueue.Dequeue (). SomeMethodCalledFromAnotherThread () будет более вероятным кандидатом ... потому что, скорее всего, конструктор и операции добавления еще не завершены, когда вы пытаетесь удалить элемент из очереди.

На самом деле, было бы неплохо проверить SomeQueue.Count * перед удалением элемента из очереди.

Изменить: Или, что еще лучше, проверка на null перед вызовом SomeMethodCalledFromAnotherThread, предполагая, что другой ваш поток проверяет очередь в цикле ... потому что, если это не так, заблокируйте очередь до операций добавления и удаления из очереди.

MyClass mine = SomeQueue.Dequeue();

if (null != mine)
    mine.SomeMethodCalledFromAnotherThread();

* Метод расширения добавлен в .NET 3.5.

1
ответ дан 8 December 2019 в 03:53
поделиться

Несколько вещей, которые вы можете попробовать:

  1. Попробуйте инициализировать Hashtable как переменную-член (вне конструктора) и с публичным свойством с тем же именем, посмотрите, не вызывает ли кто-то его сделайте присвоение, например:

     public class MyClass {
    закрытый только для чтения Hashtable hashPrefs = new Hashtable ();
    
    общедоступный MyClass (int id)
    {
    
    }
    
    общедоступный Hashtable HashPrefs
    {
     установлен
     {
     throw new InvalidOperationException («Этого не должно происходить»);
     }
    }
    

    }

  2. Во-вторых, что это за тип SomeQueue? Это просто обычный List <>? Или это какая-то специальная самореализуемая очередь, основанная на некоторой XML / двоичной сериализации? Если да, отметили ли вы HashPrefs как [Serializable]? Или как [DataMember]?

0
ответ дан 8 December 2019 в 03:53
поделиться

На ум приходит пара идей:

  • Хэш-таблица одновременно модифицируется, что приводит к несогласованному внутреннему состоянию.
  • Вызов contains выполняет проверки равенства, которые пытаются разыменовать значение, имеющее пустое поле. Что за тип `somekey`?
0
ответ дан 8 December 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: