为什么表达式总是适用于'双重检查锁定'?

时间:2011-04-18 20:58:43

标签: c# singleton resharper

我有单个对象'Service'和两个初始化和释放它的方法:

public class BaseService
{
    protected static readonly object StaticLockObject = new object();
}

public abstract class WebServiceBase<TService> : BaseService
    where TService : System.Web.Services.Protocols.SoapHttpClientProtocol, new()
{
    protected static void EnsureServiceIsOpened()
    {
        if (Service == null)
        {
            lock (StaticLockObject)
            {
                if (Service == null)
                {
                    Service = new TService();
                }
            }
        }
    }

    protected static void EnsureServiceIsClosed()
    {
        if (Service != null)
        {
            lock (StaticLockObject)
            {
                if (Service != null) // Why expression is always true
                {
                    Service.Dispose();
                    Service = null;
                }
            }
        }
    }

对于带注释resharper的行(我使用的是5.1版),会显示一条提到的警告......

问题1:为什么?

问题2:为什么它不会在'EnsureServiceIsOpened'方法中显示“类似”消息?

感谢。

3 个答案:

答案 0 :(得分:4)

Resharper对代码进行了有限的分析,并看到两个嵌套的if语句检查完全相同。在单线程环境中,resharper的注释完全正确 - 在第一个Service之后,null无法if。当然,在多线程环境中,这不适用,因为Service可以从外部更改。在这种情况下,您应该为resharper注释代码或者压缩此文件的消息,因为它在多线程环境中不成立。

答案 1 :(得分:3)

似乎Resharper在此分析中犯了一个错误。由于Service不是局部变量,因此无法知道该表达式始终为真。

第一个版本没有出现错误的原因可能是因为双重检查锁定的习惯用法很常见,这就是它的常用形式。他们可能测试了那个案例并删除了错误的警告。

EnsureServiceIsClosed中显示的技术并不常见,因为它包含竞争条件。另一个线程可能正在使用Service指示的对象,或者在处理它之后。如果使用服务的代码在StaticLockObject上锁定,那么这是不可能的,但是如果确实采用了锁定,则没有理由在创建和处理对象时进行所有这些双重检查的锁定操作。因此,确实这个代码是有缺陷的。

答案 2 :(得分:2)

这是ReSharper 5.X代码分析引擎中的错误。 在ReSharper 6.0中修复。

顺便说一下,R​​eSharper 6带来了更多的双锁模式分析:)