Google не рассматривал подчеркивание как разделителя слов в прошлом, который я думал, было довольно сумасшедшим, но по-видимому это делает теперь. Из-за этой истории предпочтены тире. Даже при том, что подчеркивания теперь допустимы с точки зрения SEO, я все еще думаю, что тире являются лучшими.
Одно преимущество - то, что Ваше среднее число semi-computer-illiterate веб-пользователь, намного более вероятно, будет в состоянии ввести тире на клавиатуре, они даже не могут знать, каково подчеркивание.
Отражение - один из способов сделать это ( 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));
Да, к полям только для чтения можно получить доступ через отражение, и их значения могут быть изменены. Так что ответ на ваш вопрос - да, это возможно.
Однако есть много других вещей, которые также могут создавать для вас проблемы. Многопоточный код сложно написать, и проблемы, которые могут возникнуть, трудно диагностировать.
В качестве примечания: вы уверены, что не получаете ArgumentNullException
? Если somekey
равно null
, метод Hashtable.Contains
вызовет исключение ArgumentNullException
. Может, в этом проблема?
Ваши инструкции могут быть переупорядочены так, чтобы ссылка на экземпляр MyClass добавлялась в очередь до того, как она будет полностью построена. Вот статья о блокировке с двойной проверкой, которая как бы затрагивает эту тему. Из статьи:
Вэнс, руководитель группы CLR JIT, объяснил, что проблема связана с моделью памяти CLR ... По сути, модель памяти позволяет переупорядочивать энергонезависимые операции чтения \ записи, если это изменение невозможно. замечено с точки зрения одного потока.
Взгляните на System.Threading.Thread.MemoryBarrier. Возможно, вам потребуется сделать что-то вроде этого:
MyClass temp = new MyClass(1);
System.Threading.Thread.MemoryBarrier();
SomeQueue.Add(temp);
MemoryBarrier гарантирует, что все инструкции перед ним будут выполнены перед продолжением.
Прежде всего, другой поток не может получить доступ к экземпляру, пока конструктор не будет завершен, поскольку сам экземпляр не будет назначен, пока конструктор не будет завершен. При этом другой поток может получить доступ к переменной , содержащей экземпляр, до завершения работы конструктора, но в то время он будет 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
Совершенно другая возможность состоит в том, что значения переменной экземпляра кэшируются в потоке специфическим образом. Если вы не блокируете (что создает барьер памяти),
Вы уверены, что исключение выдает именно HashPrefs.Contains, а не то, что представляет собой somekey? Если нет, не могли бы вы опубликовать полную информацию об исключении, возвращенную его методом ToString?
Просто выполните
HashPrefs = Hashtable.Synchronized(new Hashtable());
Нет необходимости изобретать велосипед.
Вы абсолютно уверены, что HashPrefs.Contains
бросает NPE? Я бы подумал, что SomeQueue.Dequeue (). SomeMethodCalledFromAnotherThread ()
будет более вероятным кандидатом ... потому что, скорее всего, конструктор и операции добавления еще не завершены, когда вы пытаетесь удалить элемент из очереди.
На самом деле, было бы неплохо проверить SomeQueue.Count
* перед удалением элемента из очереди.
Изменить:
Или, что еще лучше, проверка на null перед вызовом SomeMethodCalledFromAnotherThread, предполагая, что другой ваш поток проверяет очередь в цикле ... потому что, если это не так, заблокируйте
очередь до операций добавления и удаления из очереди.
MyClass mine = SomeQueue.Dequeue();
if (null != mine)
mine.SomeMethodCalledFromAnotherThread();
* Метод расширения добавлен в .NET 3.5.
Несколько вещей, которые вы можете попробовать:
Попробуйте инициализировать Hashtable как переменную-член (вне конструктора) и с публичным свойством с тем же именем, посмотрите, не вызывает ли кто-то его сделайте присвоение, например:
public class MyClass {
закрытый только для чтения Hashtable hashPrefs = new Hashtable ();
общедоступный MyClass (int id)
{
}
общедоступный Hashtable HashPrefs
{
установлен
{
throw new InvalidOperationException («Этого не должно происходить»);
}
}
}
Во-вторых, что это за тип SomeQueue? Это просто обычный List <>? Или это какая-то специальная самореализуемая очередь, основанная на некоторой XML / двоичной сериализации? Если да, отметили ли вы HashPrefs как [Serializable]? Или как [DataMember]?
На ум приходит пара идей: