为什么ReSharper告诉我这个表达总是正确的?

时间:2015-06-08 03:15:18

标签: c# resharper boolean-logic roslyn

我有以下代码,它会告诉我代码中的其他地方是否使用了某个属性。这背后的想法是验证具有private setter的属性是否可以只读。

这里有多个陷阱,但主要的是在构造函数之外对属性的赋值意味着它不会被激发。此外,静态属性可能只在静态构造函数中具有赋值以触发诊断。同样,实例属性只需要一个实例构造函数。

现在,到目前为止我已经考虑了大多数场景,但ReSharper在这段代码中给了我一个警告,我似乎无法弄清楚它的逻辑。上面的规范在这段代码中翻译:

var isStaticProperty = propertySymbol.IsStatic;
bool hasInstanceUsage = false;
bool hasStaticUsage = false;

foreach (var identifier in outerClass.DescendantNodes().OfType<IdentifierNameSyntax>())
{
   var memberSymbol = context.SemanticModel.GetSymbolInfo(identifier);
   if (memberSymbol.Symbol.Equals(propertySymbol))
   {
       var constructor = identifier.Ancestors().OfType<ConstructorDeclarationSyntax>()
                                               .FirstOrDefault();
       var isInConstructor = constructor != null;
       var isAssignmentExpression = identifier.Ancestors()
                                               .OfType<AssignmentExpressionSyntax>()
                                               .FirstOrDefault() != null;

       // Skip anything that isn't a setter
       if (!isAssignmentExpression)
       {
           continue;
       }

       // if it is a setter but outside the constructor, we don't report any diagnostic
       if (!isInConstructor)
       {
           return;
       }

       var isStaticConstructor = context.SemanticModel
                                        .GetDeclaredSymbol(constructor).IsStatic;
       if (isStaticConstructor && isStaticProperty)
       {
           hasStaticUsage = true;
       }

       if (!isStaticConstructor && !isStaticProperty)
       {
           hasInstanceUsage = true;
       }
   }
}

// We can't set it to readonly if it's set in both the instance 
//   and the static constructor
// We need a NAND operation: either it's never set, 
//   it's set in ctor 1 or it's set in ctor 2
if (!(hasStaticUsage & hasInstanceUsage))
{
   context.ReportDiagnostic(Diagnostic.Create(
                 Rule, property.Identifier.GetLocation(), propertySymbol.Name));
}

警告

  

表达始终是真的

就行了

if (!(hasStaticUsage & hasInstanceUsage))

为什么会显示此警告?有一个未知数量的后代,所以有不明数量的循环。每个循环可以将hasStaticUsagehasInstanceUsage设置为true,这意味着在2个循环(最早)之后,两个值都可能变为true,if条件将失败: NAND返回truetruetruefalse

这是我打算完成的布尔逻辑:

+----------------+------------------+--------+
| hasStaticUsage | hasInstanceUsage | result |
+----------------+------------------+--------+
| false          | false            | true   |
| false          | true             | true   |
| true           | false            | true   |
| true           | true             | false  |
+----------------+------------------+--------+

3 个答案:

答案 0 :(得分:25)

isStaticProperty在循环之外初始化:

var isStaticProperty = propertySymbol.IsStatic;

如果isStaticProperty为false,则表达式为:

 (isStaticConstructor && isStaticProperty)

始终为false,因此hasStaticUsage为false。

如果isStaticProperty为真,那么这个表达式为:

 (!isStaticConstructor && !isStaticProperty)

始终为false,因此hasInstanceUsage为false。

在任何情况下,hasStaticUsagehasInstanceUsage都不能同时为真。

答案 1 :(得分:14)

您可以通过为此表达式创建真值表来找到答案。 isStaticConstructor && isStaticProperty!isStaticConstructor && !isStaticProperty。让我们一起做。

isStaticConstructor&amp;&amp; isStaticProperty

+---------------------+------------------+--------+
| isStaticConstructor | isStaticProperty | result |
+---------------------+------------------+--------+
| false               | false            | false  |
| false               | true             | false  |
| true                | false            | false  |
| true                | true             | true   |
+---------------------+------------------+--------+

!isStaticConstructor&amp;&amp; !isStaticProperty

+---------------------+------------------+--------+
| isStaticConstructor | isStaticProperty | result |
+---------------------+------------------+--------+
| false               | false            | true   |
| false               | true             | false  |
| true                | false            | false  |
| true                | true             | false  |
+---------------------+------------------+--------+

所以你可以看到,isStaticConstructor && isStaticProperty!isStaticConstructor && !isStaticProperty都不可能true

因此,根据您提供的真值表,!(hasStaticUsage & hasInstanceUsage)成为false的唯一可能性是两个表达式同时为true,这是不可能的。

答案 2 :(得分:10)

此块使您无法将这两个变量都设置为true

if (isStaticConstructor && isStaticProperty)
{
     hasStaticUsage = true;
}

if (!isStaticConstructor && !isStaticProperty)
{
    hasInstanceUsage = true;
}

只能将其中一个变量设置为true。因此,您的if语句将始终相当于!false == true