c# resharper boolean-logic roslyn

c# - ¿Por qué ReSharper me dice que esta expresión es siempre cierta?



boolean-logic roslyn (3)

Tengo el siguiente código que me dirá si una propiedad determinada se usa o no en otra parte del código. La idea detrás de esto es verificar si una propiedad con un establecedor private se puede hacer de solo lectura.

Hay múltiples errores aquí, pero los más importantes son que una asignación a la propiedad fuera del constructor significa que no se activará. Además, una propiedad estática solo puede tener una asignación en un constructor estático para disparar el diagnóstico. Del mismo modo, una propiedad de instancia requiere solo un constructor de instancia.

Ahora, la mayoría de los escenarios que tengo hasta ahora se tienen en cuenta, pero ReSharper me da una advertencia en este fragmento de código y parece que no puedo entender su lógica. La especificación anterior se traduce en este bit de código:

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)); }

Con la advertencia siendo

La expresión es siempre cierta.

en la línea

if (!(hasStaticUsage & hasInstanceUsage))

¿Por qué muestra esta advertencia? Hay una cantidad desconocida de descendientes, así que hay una cantidad desconocida de bucles. Cada bucle puede establecer hasStaticUsage o hasInstanceUsage en true , lo que significa que después de 2 bucles (lo antes posible), ambos valores podrían convertirse en true y la condición if debería fallar: una NAND devuelve true , true , true , false .

Esta es la lógica booleana que pretendo lograr:

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


Este bloque hace imposible que alguna vez establezca ambas variables en true :

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

Solo una de las variables puede establecerse como true . Por lo tanto, su sentencia if siempre será el equivalente de !false == true .


Puedes encontrar la respuesta creando una tabla de verdad para estas expresiones. isStaticConstructor && isStaticProperty y !isStaticConstructor && !isStaticProperty . Hagámoslo juntos.

isStaticConstructor && isStaticProperty

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

! isStaticConstructor &&! isStaticProperty

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

Así que pueden ver, que no hay ninguna posibilidad de que tanto la isStaticConstructor && isStaticProperty como la !isStaticConstructor && !isStaticProperty sean !isStaticConstructor && !isStaticProperty de la true .

Entonces, dependiendo de la tabla de verdad que proporcionó, la única posibilidad de que !(hasStaticUsage & hasInstanceUsage) vuelva false es cuando ambas expresiones son true al mismo tiempo, lo cual es imposible.


isStaticProperty se inicializa fuera del bucle:

var isStaticProperty = propertySymbol.IsStatic;

Si isStaticProperty es falso, entonces esta expresión:

(isStaticConstructor && isStaticProperty)

Siempre es falso, por hasStaticUsage tanto hasStaticUsage es falso.

Si isStaticProperty es verdadero, entonces esta expresión:

(!isStaticConstructor && !isStaticProperty)

Siempre es falso, por hasInstanceUsage tanto hasInstanceUsage es falso.

En cualquier caso, hasStaticUsage y hasInstanceUsage no pueden ser verdaderas al mismo tiempo.