'使用'声明vs'尝试终于'

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.

将变量放在范围内,在不再需要之后立即结束也是一个加分.

  • @bjan好吧,为什么你甚至考虑在这种情况下使用`using`?这不是"使用"的用途. (2认同)

Rob*_*ker 12

我绝对更喜欢第二种方法.它在使用方面更简洁,更不容易出错.

在第一种情况下,有人编辑代码时必须注意不要在Acquire(读|写)锁定调用和try之间插入任何内容.

(对这样的单个属性使用读/写锁定通常是矫枉过正.它们最好应用在更高的级别.一个简单的锁定通常就足够了,因为考虑到锁定的时间,争用的可能性非常小对于和获取读/写锁是一种比简单锁更昂贵的操作.


Ste*_*owe 8

考虑两种解决方案都不好的可能性,因为它们掩盖了异常.

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可以提供帮助;-)

  • 它不会掩盖异常,它将以与您的异常完全相同的方式替换异常. (3认同)
  • 最后尝试并不一定掩盖异常。在我的示例中,获取了锁,然后,如果在范围内引发任何异常,则将释放该锁,但该异常仍会冒泡。 (2认同)

Rob*_*ams 5

我个人尽可能经常使用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作为我的主要语言,其中有很多其他语言,并且"使用"是我最喜欢的语言功能之一,因为它是一个实用的,日常的主力.