特定のプロパティがコードの他の場所で使用されているかどうかを示す次のコードがあります。この背後にある考え方は、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'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))
なぜこの警告が表示されるのですか?子孫の数が不明であるため、ループの数が不明です。各ループはhasStaticUsage
またはhasInstanceUsage
をtrue
に設定できます。つまり、2つのループの後(早くても)、両方の値がtrue
になります。条件は失敗するはずです:NANDはtrue
、true
、true
、false
を返します。
これは、私が達成しようとしているブール論理です。
+----------------+------------------+--------+
| hasStaticUsage | hasInstanceUsage | result |
+----------------+------------------+--------+
| false | false | true |
| false | true | true |
| true | false | true |
| true | true | false |
+----------------+------------------+--------+
isStaticProperty
はループの外側で初期化されます:
var isStaticProperty = propertySymbol.IsStatic;
isStaticProperty
がfalseの場合、次の式は次のとおりです。
(isStaticConstructor && isStaticProperty)
は常にfalseであるため、hasStaticUsage
はfalseです。
isStaticProperty
がtrueの場合、次の式は次のとおりです。
(!isStaticConstructor && !isStaticProperty)
は常にfalseであるため、hasInstanceUsage
はfalseです。
いずれにせよ、hasStaticUsage
とhasInstanceUsage
の両方を同時に真にすることはできません。
この式の真理値表を作成することで、答えを見つけることができます。 _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
である場合であり、これは不可能です。
このブロックにより、これらの変数の両方をtrue
に設定することは不可能になります。
if (isStaticConstructor && isStaticProperty)
{
hasStaticUsage = true;
}
if (!isStaticConstructor && !isStaticProperty)
{
hasInstanceUsage = true;
}
true
に設定できる変数は1つだけです。したがって、if
ステートメントは常に!false == true
と同等になります。