2015-06-08 29 views
20

Mam następujący kod, który powie mi, czy dana właściwość jest używana w innym miejscu kodu. Pomysł polega na sprawdzeniu, czy właściwość z ustawiaczem private może być wykonana tylko do odczytu.Dlaczego ReSharper mówi mi, że to wyrażenie jest zawsze prawdziwe?

Jest tu wiele kuponów, ale najważniejsze jest to, że przydział do nieruchomości poza konstruktorem oznacza, że ​​nie będzie strzelał. Ponadto właściwość statyczna może mieć tylko przypisanie w konstruktorze statycznym, aby uruchomić diagnostykę. Podobnie właściwość instancji wymaga tylko konstruktora instancji.

Obecnie większość scenariuszy, które dotąd miałem, zostało uwzględnionych, ale ReSharper daje mi ostrzeżenie w tym kodzie i nie mogę pojąć jego logiki. Powyższa specyfikacja jest tłumaczone w ten bit kodu:

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

z ostrzeżeniem będącego

Expression jest zawsze prawdziwe

na linii

if (!(hasStaticUsage & hasInstanceUsage)) 

dlaczego pokazuje to ostrzeżenie? Istnieje nieznana liczba potomków, więc istnieje nieznana liczba pętli. Każda pętla może ustawić hasStaticUsage lub hasInstanceUsage do true, co oznacza, że ​​po 2 pętle (najwcześniej), obie wartości może stać true a jeśli warunek nie powinien: a NAND zwraca true, true, true, false.

To jest logiczna logika Zamierzam zrealizować:

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

Gdzie jest zainicjalizowane 'isStaticProperty'? –

+0

Na tym samym poziomie 'hasInstanceUsage'. Uwzględnię to dla kompletności, ale nie sądzę, że ma to wpływ. –

+0

'Mam następujący kod, który powie mi, czy dana właściwość jest używana gdzie indziej w kodzie" - czy nie jest to natywna funkcja w VS? – Davor

Odpowiedz

25

isStaticProperty jest inicjowany na zewnątrz pętli:

var isStaticProperty = propertySymbol.IsStatic; 

Jeśli isStaticProperty jest fałszywy, to wyrażenie:

(isStaticConstructor && isStaticProperty) 

zawsze jest fałszywy, stąd hasStaticUsage fałszywe.

Jeśli isStaticProperty jest prawdą, to wyrażenie:

(!isStaticConstructor && !isStaticProperty) 

jest zawsze fałszywe, stąd hasInstanceUsage jest fałszywe.

W każdym przypadku hasStaticUsage i hasInstanceUsage nie mogą jednocześnie mieć wartości true.

10

Blok ten sprawia, że ​​niemożliwe, że będzie kiedykolwiek ustawić zarówno tych zmiennych true:

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

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

Tylko jedna ze zmiennych można ustawić na true. Tak więc Twoja instrukcja if zawsze będzie odpowiednikiem !false == true.

+0

Ostrzeżenie nadal występuje. –

+0

@JeroenVannevel zobacz moją edycję. Masz problem logiczny w innym miejscu kodu. –

+0

Okazuje się, że było to spowodowane tym boolean 'isStaticProperty', którego całkowicie przeoczyłem. Doceniam, że wyszukujesz ze mną. –

14

Możesz znaleźć odpowiedź, tworząc tabelę prawdy dla tego wyrażenia. isStaticConstructor && isStaticProperty i !isStaticConstructor && !isStaticProperty. Zróbmy to razem.

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 | 
+---------------------+------------------+--------+ 

Tak więc widać, że nie ma żadnej możliwości, że zarówno isStaticConstructor && isStaticProperty i !isStaticConstructor && !isStaticProperty to true.

Tak więc, w zależności od podanej tabeli prawdy, jedyną możliwością, że !(hasStaticUsage & hasInstanceUsage) staje się false jest, gdy oba wyrażenia są w tym samym czasie true, co jest niemożliwe.

+0

To była rzeczywiście przyczyna - po prostu nie nawiązałem połączenia z 'isStaticProperty' i zapomniałem, że nie mogło się zmienić podczas cykli. –