Почему ReSharper говорит мне, что это выражение всегда верно?
У меня есть следующий код, который скажет мне, используется ли какое-либо свойство в другом месте кода. Идея этого заключается в том, чтобы проверить, может ли свойство с установщиком private
быть только для чтения.
Здесь есть несколько исправлений, но главные из них состоят в том, что присвоение свойства вне конструктора означает, что он не срабатывает. Кроме того, статическое свойство может иметь только назначение в статическом конструкторе для запуска диагностики. Аналогично, для свойства экземпляра требуется только конструктор экземпляра.
В настоящее время большинство сценариев, которые я до сих пор учитывал, пока не 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 set in both the instance
// and the static constructor
// We need a NAND operation: either it never set,
// it set in ctor 1 or it set in ctor 2
if (!(hasStaticUsage & hasInstanceUsage))
{
context.ReportDiagnostic(Diagnostic.Create(
Rule, property.Identifier.GetLocation(), propertySymbol.Name));
}
При наличии предупреждения
Выражение всегда истинно
на линии
if (!(hasStaticUsage & hasInstanceUsage))
Почему это предупреждение? Есть неизвестное количество потомков, так что неизвестное количество петель. Каждый цикл может установить hasStaticUsage
или hasInstanceUsage
в true
, что означает, что после двух циклов (как можно раньше) оба значения могут стать true
, а условие if должно завершиться неудачно: NAND возвращает true
, true
, true
, false
.
Это логическая логика, которую я намереваюсь выполнить:
+----------------+------------------+--------+
| hasStaticUsage | hasInstanceUsage | result |
+----------------+------------------+--------+
| false | false | true |
| false | true | true |
| true | false | true |
| true | true | false |
+----------------+------------------+--------+
Ответы
Ответ 1
isStaticProperty
инициализируется вне цикла:
var isStaticProperty = propertySymbol.IsStatic;
Если isStaticProperty
является ложным, то это выражение:
(isStaticConstructor && isStaticProperty)
всегда false, поэтому hasStaticUsage
является ложным.
Если isStaticProperty
истинно, то это выражение:
(!isStaticConstructor && !isStaticProperty)
всегда false, поэтому hasInstanceUsage
является ложным.
В любом случае hasStaticUsage
и hasInstanceUsage
не могут одновременно быть истинными.
Ответ 2
Вы можете найти ответ, создав таблицу истинности для этих выражений.
isStaticConstructor && isStaticProperty
и !isStaticConstructor && !isStaticProperty
. Давайте сделаем это вместе.
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 |
+---------------------+------------------+--------+
Итак, вы можете видеть, что нет возможности, чтобы оба isStaticConstructor && isStaticProperty
и !isStaticConstructor && !isStaticProperty
были true
.
Итак, в зависимости от таблицы правды, которую вы предоставили, единственная возможность, что !(hasStaticUsage & hasInstanceUsage)
становится false
, - это когда оба выражения true
в одно и то же время, что невозможно.
Ответ 3
Этот блок делает невозможным, чтобы вы установили обе эти переменные в true
:
if (isStaticConstructor && isStaticProperty)
{
hasStaticUsage = true;
}
if (!isStaticConstructor && !isStaticProperty)
{
hasInstanceUsage = true;
}
Только одна из переменных может быть установлена на true
. Таким образом, ваш оператор if
всегда будет эквивалентен !false == true
.