Из MSDN Оператор использования (Ссылка C#)
оператор использования гарантирует, чтобы Расположили, назван, даже если исключение происходит, в то время как Вы - вызывающие методы для объекта. Можно достигнуть того же результата путем помещения объекта в блоке попытки, и затем вызов Располагают в наконец блок; на самом деле это - то, как оператор использования переводится компилятором. Пример кода ранее расширяется до следующего кода во время компиляции (отметьте дополнительные фигурные скобки для создания ограниченного объема для объекта):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
Так в основном, это - тот же код, но с хорошие автоматические пустые проверки и дополнительный объем для Вашей переменной . Документация также указывает, что "гарантирует корректное использование объекта IDisposable", таким образом, Вы могли бы также получать еще лучшую поддержку платформы для любых неясных случаев в будущем.
Так идут с опцией 2.
, Имеющей переменную внутренняя часть объем , который сразу заканчивается после того, как это больше не необходимо, также плюс.
Я думаю, что метод 2 был бы лучше.
В то время как я соглашаюсь со многими вышеупомянутыми комментариями, включая гранулярность блокировки и сомнительную обработку исключений, вопросом является один из подхода. Позвольте мне привести Вам одну большую причину, почему я предпочитаю использовать по попытке {} наконец модель... абстракция.
у меня есть модель, очень похожая на Ваш за одним исключением. Я определил основной интерфейс ILock, и в нем я обеспечил, один метод под названием Получают (). Получение () метод возвратил объект IDisposable и в результате означает, что, пока объект, с которым я имею дело, имеет тип ILock, что это может использоваться, чтобы сделать объем блокировки. Почему это важно?
Мы имеем дело со многими различными механизмами блокировки и поведениями. Ваш объект блокирования может иметь определенный тайм-аут, который использует. Ваша реализация блокировки может быть блокировкой монитора, блокировкой читателя, блокировкой писателя или спин-блокировкой. Однако с точки зрения вызывающей стороны все это не важно, о чем они заботятся, то, что контракт для блокировки ресурса соблюдают и что блокировка делает это способом, согласовывающимся с, он - реализация.
interface ILock {
IDisposable Acquire();
}
class MonitorLock : ILock {
IDisposable Acquire() { ... acquire the lock for real ... }
}
мне нравится Ваша модель, но я рассмотрел бы сокрытие механики блокировки от вызывающей стороны. FWIW, я измерил издержки метода использования по сравнению с попыткой наконец, и издержки выделения доступного объекта будут иметь между 2-3% производительности наверху.
DRY говорит: второе решение. Первое решение копирует логику использования блокировки, тогда как второе не делает.
Мне нравится 3-я опция
private object _myDateTimeLock = new object();
private DateTime _myDateTime;
public DateTime MyDateTime{
get{
lock(_myDateTimeLock){return _myDateTime;}
}
set{
lock(_myDateTimeLock){_myDateTime = value;}
}
}
Ваших двух опций, вторая опция является самой чистой и легче понять то, что продолжается.
"Набор свойств" и блокирующий в методе get свойства и уровне метода set смотрит неправильно. Ваша блокировка является слишком мелкомодульной. В самом типичном объектном использовании Вы хотели бы удостовериться, что Вы получили блокировку к доступу [еще 110] , чем одно свойство одновременно. Ваш конкретный случай мог бы отличаться, но я вид сомнения это.
Так или иначе, получая блокировку, когда Вы получаете доступ к объекту вместо свойства, значительно сократит объем блокировки кода, который необходимо будет записать.
Рассмотрите возможность, что оба решения плохи, потому что они маскируют исключения .
А try
без catch
должен, очевидно, быть плохой идеей; см. MSDN для того, почему using
оператор аналогично опасен.
Примечание также Microsoft теперь рекомендует ReaderWriterLockSlim вместо ReaderWriterLock.
Наконец, обратите внимание, что примеры Microsoft используют два блока try-catch для предотвращения этих проблем, например,
try
{
try
{
//Reader-writer lock stuff
}
finally
{
//Release lock
}
}
catch(Exception ex)
{
//Do something with exception
}
А простым, последовательным, чистым решением является хорошая цель, но принятие Вас не может только использовать lock(this){return mydateetc;}
, Вы могли бы пересмотреть подход; с большим количеством информации я уверен Stack Переполнение может помочь;-)
Я лично использую оператор "использования" C# максимально часто, но существует несколько определенных вещей, которые я делаю наряду с ним для предотвращения потенциальных упомянутых проблем. Проиллюстрировать:
void doSomething()
{
using (CustomResource aResource = new CustomResource())
{
using (CustomThingy aThingy = new CustomThingy(aResource))
{
doSomething(aThingy);
}
}
}
void doSomething(CustomThingy theThingy)
{
try
{
// play with theThingy, which might result in exceptions
}
catch (SomeException aException)
{
// resolve aException somehow
}
}
Примечание, что я разделяю оператор "использования" на один метод и использование объекта (объектов) в другой метод с "попыткой" / блок "выгоды". Я могу вложить несколько операторов "использования" как это для связанных объектов (я иногда иду три или четыре глубоко в моем производственном коде).
В моем Dispose()
методы для этих пользовательских IDisposable
классы, я ловлю исключения (но НЕ ошибки) и регистрирую их (использующий Log4net). Я никогда не встречался с ситуацией, где любое из тех исключений могло возможно влиять на мою обработку. Потенциальным ошибкам, как обычно, позволяют распространить стек вызовов и обычно оконечную обработку с соответствующим сообщением (ошибка и отслеживание стека) зарегистрированный.
, Если я так или иначе встретился с ситуацией, где значительное исключение могло произойти во время Dispose()
, я перепроектирую для той ситуации. Откровенно говоря, я сомневаюсь, что это будет когда-либо происходить.
Между тем, объем и преимущества очистки "использования" делают его одной из моих самых любимых функций C#. Между прочим, я работаю в Java, C# и Python как мои основные языки, с большим количеством других, добавленных тут и там, и "использование" является одной из моих самых любимых функций языка все вокруг, потому что это - практическая, повседневная рабочая лошадь.
Я определенно предпочитаю второй метод. Это более кратко при использовании и менее подвержено ошибкам.
В первом случае кто-то редактирующий код должен бояться вставлять что-либо между Получением (Read|Write) вызов Блокировки и попыткой.
(Используя чтение-запись соединяют отдельные свойства как это, обычно излишество все же. Они лучше всего применяются в намного более высоком уровне. Простая блокировка будет часто достаточна здесь, так как возможность конкуренции является, по-видимому, очень маленькой, учитывая время, для которого сохранена блокировка, и получение блокировки чтения-записи является более дорогой операцией, чем простая блокировка).
Блоки попытки/Выгоды обычно для обработки исключений, в то время как использование блоков используется, чтобы гарантировать, что объект расположен.
Для блокировки чтения-записи попытка/выгода могла бы быть самой полезной, но Вы могли также использовать обоих, как так:
using (obj)
{
try { }
catch { }
}
так, чтобы можно было неявно назвать интерфейс IDisposable, а также сделать обработку исключений краткой.
Глупый я. Есть способ сделать это еще проще, сделав заблокированные методы частью каждого экземпляра (вместо статических, как в моем предыдущем посте). Сейчас я действительно предпочитаю это, потому что нет необходимости передавать `rwlMyLock_m 'какому-либо другому классу или методу.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private DateTime ReadLockedMethod(ReadLockMethod method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(WriteLockMethod method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}
SoftwareJedi, у меня нет учетной записи, поэтому я не могу редактировать свои ответы.
В любом случае предыдущая версия не очень подходила для общего использования, так как блокировка чтения всегда требовала возвращаемого значения. Это устраняет следующее:
class StackOTest
{
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
DateTime retval = default(DateTime);
ReadLockedMethod(
delegate () { retval = dtMyDateTime_m; }
);
return retval;
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private void ReadLockedMethod(Action method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(Action method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}
Я удивлен, что никто не предложил инкапсулировать try-finally в анонимные функции. Подобно технике создания экземпляров и удаления классов с помощью оператора using, блокировка сохраняется в одном месте. Я предпочитаю это сам только потому, что я предпочитаю читать слово «наконец», чем слово «удалить», когда я думаю о снятии блокировки.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
rwlMyLock_m,
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
rwlMyLock_m,
delegate () { dtMyDateTime_m = value; }
);
}
}
private static DateTime ReadLockedMethod(
ReaderWriterLock rwl,
ReadLockMethod method
)
{
rwl.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwl.ReleaseReaderLock();
}
}
private static void WriteLockedMethod(
ReaderWriterLock rwl,
WriteLockMethod method
)
{
rwl.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwl.ReleaseWriterLock();
}
}
}