Jer*_*emy 74 .net c# multithreading using-statement
我有一堆属性,我将使用读/写锁.我可以使用a try finally或a using子句来实现它们.
在try finally我之前try,我将获得锁定,然后释放finally.在该using子句中,我将创建一个在其构造函数中获取锁的类,并在其Dispose方法中释放.
我在很多地方使用读/写锁,所以我一直在寻找可能更简洁的方法try finally.我有兴趣听听一些关于为什么不推荐一种方式的想法,或者为什么一种方式可能比另一方更好.
方法1(try finally):
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
rwlMyLock_m .AcquireReaderLock(0);
try
{
return dtMyDateTime_m
}
finally
{
rwlMyLock_m .ReleaseReaderLock();
}
}
set
{
rwlMyLock_m .AcquireWriterLock(0);
try
{
dtMyDateTime_m = value;
}
finally
{
rwlMyLock_m .ReleaseWriterLock();
}
}
}
Run Code Online (Sandbox Code Playgroud)
方法2:
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
using (new ReadLock(rwlMyLock_m))
{
return dtMyDateTime_m;
}
}
set
{
using (new WriteLock(rwlMyLock_m))
{
dtMyDateTime_m = value;
}
}
}
public class ReadLock : IDisposable
{
private ReaderWriterLock rwl;
public ReadLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireReaderLock(0);
}
public void Dispose()
{
rwl.ReleaseReaderLock();
}
}
public class WriteLock : IDisposable
{
private ReaderWriterLock rwl;
public WriteLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireWriterLock(0);
}
public void Dispose()
{
rwl.ReleaseWriterLock();
}
}
Run Code Online (Sandbox Code Playgroud)
cha*_*rit 87
从MSDN,使用Statement(C#参考)
using语句确保即使在对象上调用方法时发生异常,也会调用Dispose.您可以通过将对象放在try块中然后在finally块中调用Dispose来实现相同的结果; 实际上,这就是编译器如何翻译using语句.前面的代码示例在编译时扩展为以下代码(注意额外的花括号以创建对象的有限范围):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
所以基本上,它是相同的代码,但有一个很好的自动空值检查和一个额外的变量范围.该文档还指出它"确保正确使用IDisposable对象",因此您可能会为将来任何模糊的案例获得更好的框架支持.
所以选择2.
将变量放在范围内,在不再需要之后立即结束也是一个加分.
Rob*_*ker 12
我绝对更喜欢第二种方法.它在使用方面更简洁,更不容易出错.
在第一种情况下,有人编辑代码时必须注意不要在Acquire(读|写)锁定调用和try之间插入任何内容.
(对这样的单个属性使用读/写锁定通常是矫枉过正.它们最好应用在更高的级别.一个简单的锁定通常就足够了,因为考虑到锁定的时间,争用的可能性非常小对于和获取读/写锁是一种比简单锁更昂贵的操作.
考虑两种解决方案都不好的可能性,因为它们掩盖了异常.
try没有a的A 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
}
Run Code Online (Sandbox Code Playgroud)
一个简单,一致,干净的解决方案是一个很好的目标,但假设您不能只使用lock(this){return mydateetc;},您可能会重新考虑这种方法; 更多信息我确定Stack Overflow可以提供帮助;-)
我个人尽可能经常使用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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,我将"using"语句分隔为一个方法,并将对象用于另一个带有"try"/"catch"块的方法.我可以为相关对象嵌套几个"using"语句(我有时会在我的生产代码中深入三到四个).
在我Dispose()的这些自定义IDisposable类的方法中,我捕获异常(但不是错误)并记录它们(使用Log4net).我从未遇到任何这些异常可能影响我的处理的情况.像往常一样,潜在的错误被允许向上传播调用堆栈,并且通常在记录了适当的消息(错误和堆栈跟踪)的情况下终止处理.
如果我在某种程度上遇到了可能发生重大异常的情况Dispose(),我会重新设计这种情况.坦率地说,我怀疑这种情况会不会发生.
同时,"使用"的范围和清理优势使其成为我最喜欢的C#功能之一.顺便说一句,我使用Java,C#和Python作为我的主要语言,其中有很多其他语言,并且"使用"是我最喜欢的语言功能之一,因为它是一个实用的,日常的主力.