2017-02-01 2 views
1

Der folgende Code ist ein vereinfachter Auszug aus einem Teil unseres Produktionscodes. Es berechnet die SHA256-Hash für eine Datei und gibt ihn als String oder zurückgibt null wenn die Datei nicht zugegriffen werden kann:Ausnahmefilter verursacht CA2000 trotz einer using-Anweisung

private static string CalculateHash(string fileName) 
{ 
    try 
    { 
     string result; 
     using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) 
     { 
      byte[] data = File.ReadAllBytes(fileName); 
      result = BitConverter.ToString(sha256.ComputeHash(data)); 
     } 

     Debug.WriteLine("Calculated hash for '" + fileName + "': " + result, 3); 
     return result; 
    } 
    catch (UnauthorizedAccessException ex) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
    catch (IOException ex) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
} 

Einer unserer Entwickler Refactoring vor kurzem den Code mit einer Ausnahme Filter die doppelten catch Blöcke zu reduzieren es sieht aus, so dass nun wie folgt aus:

private static string CalculateHash(string fileName) 
{ 
    try 
    { 
     string result; 
     using (SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider()) 
     { 
      byte[] data = File.ReadAllBytes(fileName); 
      result = BitConverter.ToString(sha256.ComputeHash(data)); 
     } 

     Debug.WriteLine("Calculated hash for '" + fileName + "': " + result, 3); 
     return result; 
    } 
    catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException) 
    { 
     Debug.WriteLine("The hash calculation failed: " + ex.Message, 3); 
     return null; 
    } 
} 

aber wir nun eine Code-Analyse-Warnung erhalten:

CA2000 - In Verfahren 'CalculateHash (string)', System.IDisposable nennen. Entsorgen Sie das Objekt 'sha256', bevor alle Verweise darauf außerhalb des Bereichs liegen.

Soweit ich sehen kann, ist die SHA256CryptoServiceProvider richtig hier angeordnet ist, und das wird passieren, ob die Ausnahme durch die Filter aufgefangen wird oder nicht.

Ist diese CA2000 falsch positiv oder hat der Ausnahmefilter ein Szenario erstellt, in dem die Entsorgung nicht stattfindet?

+0

Ich bekomme auch 'CA2202' mit' wenn' in Ihrem Beispiel (kommentieren wird es alle Warnungen beseitigen). Scheint wie Code-Analyse-Problem. 'finally' (von [' using'] (https://msdn.microsoft.com/en-us/library/yh598w02.aspx)) wird garantiert vor jedem ** äußeren ** 'catch' laufen. – Sinatr

Antwort

0

Es sieht wie ein falsch-positive aus und kann sicher unterdrückt werden.

Ich habe die Intermediate Language für beide Versionen der Methode verglichen. Beide zeigen die using Anweisung als try/finally Block, der das Objekt korrekt entsorgt. Tatsächlich ist die IL für beide Methoden identisch, mit Ausnahme der äußeren Catch/Exception-Filtersektion.

.try 
{ 
    IL_0000: newobj  instance void [System.Core]System.Security.Cryptography.SHA256CryptoServiceProvider::.ctor() 
    IL_0005: stloc.1 V_1 
    .try 
    { 
    IL_0006: ldarg.0 fileName 
    IL_0007: call   unsigned int8[] [mscorlib]System.IO.File::ReadAllBytes(string) 
    IL_000c: stloc.2 'buffer [Range(Instruction(IL_000c stloc.2)-Instruction(IL_000e ldloc.2))]' 
    IL_000d: ldloc.1 V_1 
    IL_000e: ldloc.2 'buffer [Range(Instruction(IL_000c stloc.2)-Instruction(IL_000e ldloc.2))]' 
    IL_000f: callvirt  instance unsigned int8[] [mscorlib]System.Security.Cryptography.HashAlgorithm::ComputeHash(unsigned int8[]) 
    IL_0014: call   string [mscorlib]System.BitConverter::ToString(unsigned int8[]) 
    IL_0019: stloc.0 'string [Range(Instruction(IL_0019 stloc.0)-Instruction(IL_0026 ldloc.0))]' 
    IL_001a: leave.s  IL_0026 
    } // end of .try 
    finally 
    { 
    IL_001c: ldloc.1 V_1 
    IL_001d: brfalse.s IL_0025 
    IL_001f: ldloc.1 V_1 
    IL_0020: callvirt  instance void [mscorlib]System.IDisposable::Dispose() 
         /* ^^ here we can see the Dipose method being called 
         * in the finally block 
         */ 
    IL_0025: endfinally 
    } // end of finally 
    IL_0026: ldloc.0 'string [Range(Instruction(IL_0019 stloc.0)-Instruction(IL_0026 ldloc.0))]' 
    IL_0027: stloc.3 V_3 
    IL_0028: leave.s  IL_0034 
} // end of .try 
// ... catch or exception filter IL code then appears here ... 
Verwandte Themen