CA2000: Kapsamı kaybetmeden önce nesneleri yok edin

Özellik Değer
Kural Kimliği CA2000
Başlık Kapsamdan çıkmadan önce nesneleri yok edin.
Kategori Güvenilirlik
Düzeltme bozucu ya da bozmayan olabilir Kesintisiz
.NET 10'da varsayılan olarak etkin Hayır
Geçerli diller C# ve Visual Basic

Neden

IDisposable türünde bir yerel nesne oluşturulur, ancak nesneye yapılan tüm başvurular geçerli kapsam dışına çıkmadan önce nesne imha edilmez.

Varsayılan olarak, bu kural tüm kod tabanını analiz eder, ancak bu yapılandırılabilir.

Kural açıklaması

Atılabilir bir nesnenin tüm başvuruları kapsam dışında kalmadan önce açıkça atılmazsa, atık toplayıcı nesnenin sonlandırıcısını çalıştırdığında nesne belirsiz bir zamanda atılır. Nesnenin sonlandırıcısının çalışmasını engelleyecek olağanüstü bir olay meydana gelebileceğinden, nesne açıkça yok edilmelidir.

Özel durumlar

Kural CA2000, nesne atılmasa bile aşağıdaki türlerdeki yerel nesneler için çalışmaz.

Bu türlerden birinin nesnesini bir yapıcı metoda geçirip bir alana atamak, yeni oluşturulmuş türe bir dispose sahiplik aktarımı olduğunu gösterir. Yani, yeni oluşturulmuş tür artık nesnenin imha edilmesinden sorumludur. Kodunuzdan bu türlerden birinin bir nesnesi bir oluşturucuya geçirildiğinde, nesneye yapılan tüm başvurular kapsamdan çıkmadan önce bile sonlandırılmasa, kural CA2000'e bir ihlal gerçekleşmez.

İhlalleri düzeltme

Bu kuralın ihlalini düzeltmek için, nesneye yapılan tüm başvurular kapsam dışında kalmadan önce nesne üzerinde Dispose çağrısını yapın.

using deyimini (Using Visual Basic'te) IDisposable uygulayan nesneleri sarmak için kullanabilirsiniz. Bu yöntemle sarmalanan nesneler, using bloğunun sonunda otomatik olarak atılır. Ancak, aşağıdaki durumlar bir using deyimle işlenmemelidir veya işlenemeyecektir:

  • Atılabilir bir nesne döndürmek için, nesne bir bloğun try/finally dışındaki bir using blokta oluşturulmalıdır.

  • Bir using deyiminin yapıcısında atılabilir bir nesnenin üyeleri başlatılmamalıdır.

  • Yalnızca bir özel durum işleyicisi tarafından korunan oluşturucular bir using deyimin edinim bölümünde iç içe geçirildiğinde, dış oluşturucudaki bir hata iç içe oluşturucu tarafından oluşturulan nesnenin asla kapatılmamasına neden olabilir. Aşağıdaki örnekte, StreamReader yapıcısındaki bir hata, FileStream nesnesinin hiçbir zaman kapatılmamasına neden olabilir. CA2000, bu durumda kuralın ihlalini işaret eder.

    using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
    { ... }
    
  • Dinamik nesneler, IDisposable nesnelerin bertaraf desenini uygulamak için bir gölge nesne kullanmalıdır.

Uyarıların ne zaman bastırılması gerekiyor?

Aşağıdakiler dışında bu kuraldan bir uyarıyı gizlemeyin:

  • Nesnenizde, `Close` gibi `Dispose` öğesini çağıran bir yöntem çağırdınız.
  • Uyarıyı tetikleyen yöntem, nesnenizi sarmalayan bir IDisposable nesne döndürür.
  • Ayırma yöntemi, bertaraf etme sahipliğine sahip değildir; yani, nesneyi bertaraf etme sorumluluğu, yöntem içinde oluşturulan ve çağırana döndürülen başka bir nesneye veya sarmalayıcıya aktarılır.

Uyarıyı gizleme

Yalnızca tek bir ihlali engellemek istiyorsanız, kuralı devre dışı bırakmak ve sonra yeniden etkinleştirmek için kaynak dosyanıza ön işlemci yönergeleri ekleyin.

#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000

Bir dosya, klasör veya projenin kuralını devre dışı bırakmak için, yapılandırma dosyasındaki önem derecesini noneolarak ayarlayın.

[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none

Daha fazla bilgi için bkz . Kod analizi uyarılarını gizleme.

Kod çözümleme için konfigüre et

Kod tabanınızın hangi bölümlerinde bu kuralın çalıştırılacağını ve kullanım hakkı devrinin ne zaman yapılacağını yapılandırmak için aşağıdaki seçenekleri kullanın.

Ayrıca, bu kural için aşağıdaki diğer veri akışı analiziyle ilgili seçenekler geçerlidir:

Bu seçenekleri yalnızca bu kural, uyguladıkları tüm kurallar veya bu kategorideki tüm kurallar için (Güvenilirlik) yapılandırabilirsiniz. Daha fazla bilgi için bkz . Kod kalitesi kuralı yapılandırma seçenekleri.

Belirli simgeleri hariç tutma

excluded_symbol_names seçeneğini ayarlayarak türler ve yöntemler gibi belirli simgeleri analizden hariç tutabilirsiniz. Örneğin, kuralın adlı MyTypetürlerdeki herhangi bir kodda çalışmaması gerektiğini belirtmek için, projenizdeki bir .editorconfig dosyasına aşağıdaki anahtar-değer çiftini ekleyin:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Not

XXXX CAXXXX bölümünü geçerli kuralın kimliğiyle değiştirin.

Seçenek değerinde izin verilen simge adı biçimleri (ile |ayrılmış):

  • Yalnızca sembol adı (içerildiği tür veya ad alanından bağımsız olarak ada sahip tüm simgeleri içerir).
  • Simgelerin dökümantasyon kimliği formatındaki tam adlar. Her sembol adı için, yöntemler için M:, türler için T:, ve ad alanları için N: gibi bir sembol türü ön eki gerekir.
  • .ctor oluşturucular ve .cctor statik oluşturucular için.

Örnekler:

Seçenek Değeri Özet
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType adlı MyTypetüm simgelerle eşleşir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 MyType1 veya MyType2 adlı tüm simgelerle eşleşir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Belirtilen tam imza ile belirli bir yöntemi MyMethod eşleştirir.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Belirli yöntemlerle MyMethod1 ve MyMethod2 ilgili tam imzalarla eşleşir.

Belirli türleri ve türetilmiş türlerini dışlama

excluded_type_names_with_derived_types seçeneğini ayarlayarak belirli türleri ve türetilmiş türlerini analizden dışlayabilirsiniz. Örneğin, kuralın adlı MyType ve türetilmiş türleri içindeki hiçbir yöntemde çalışmaması gerektiğini belirtmek için, projenizdeki bir .editorconfig dosyasına aşağıdaki anahtar-değer çiftini ekleyin:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Not

XXXX CAXXXX bölümünü geçerli kuralın kimliğiyle değiştirin.

Seçenek değerinde izin verilen simge adı biçimleri (ile |ayrılmış):

  • Yalnızca tür adı (içeren tür veya ad alanına bakılmaksızın adı olan tüm türleri içerir).
  • Simgenin belge kimliği biçiminde, isteğe bağlı T: ön ek içeren tam adlar.

Örnekler:

Seçenek değeri Özet
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Adı MyType olan tüm türleri ve türevlerini eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 MyType1 veya MyType2 adlı tüm türleri ve bunların türetilmiş türlerinin tamamını eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Belirli bir türü MyType verilen tam adla ve türetilmiş tüm türleriyle eşleştirir.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Belirli türler MyType1 ve MyType2 ile bunların türetilmiş tüm türleri, ilgili tam adlarla eşleşir.

Sahiplik transferini yapılandırma ve sonlandırma

dispose_ownership_transfer_at_constructor ve dispose_ownership_transfer_at_method_call seçenekleri, dispose sahipliğinin aktarımını yapılandırır.

Örneğin, kuralın oluşturuculara geçirilen bağımsız değişkenlerin dispose sahipliğini aktardığını belirtmek için projenizdeki bir .editorconfig dosyasına aşağıdaki anahtar-değer çiftini ekleyin:

dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true

Not

XXXX CAXXXX bölümünü geçerli kuralın kimliğiyle değiştirin.

Kurucu İşlevinde Sahiplik Devri Ayarını Yapma

Aşağıdaki kod örneğini göz önünde bulundurun.

class A : IDisposable
{
    public void Dispose() { }
}

class Test
{
    DisposableOwnerType M1()
    {
        return new DisposableOwnerType(new A());
    }
}
  • dotnet_code_quality.dispose_ownership_transfer_at_constructor true olarak ayarlandığında, new A() tahsisatının sahipliği, döndürülen DisposableOwnerType örneğine aktarılır.
  • dotnet_code_quality.dispose_ownership_transfer_at_constructor false olarak ayarlanırsa, Test.M1()new A() için bertaraf sahipliğini alır ve bu, bir atık sızıntısı için CA2000 ihlali oluşturur.

yöntem çağrısında sahiplik aktarımı yok et

Aşağıdaki kod örneğini göz önünde bulundurun.

class Test
{
    void M1()
    {
        TransferDisposeOwnership(new A());
    }
}
  • dotnet_code_quality.dispose_ownership_transfer_at_method_call olarak ayarlanırsa, new A() tahsis edilen kaynağın kontrolü TransferDisposeOwnership yöntemine devredilir.
  • Eğer dotnet_code_quality.dispose_ownership_transfer_at_method_call, false olarak ayarlanırsa, Test.M1(), new A() için atma sahipliğine sahiptir ve atma sızıntısına yol açarak CA2000 ihlaline neden olur.

Örnek 1

Tek kullanımlık bir nesne döndüren bir yöntem uyguluyorsanız, nesnenin atıldığından emin olmak için catch bloğu olmayan bir try/finally bloğu kullanın. Try/finally bloğu kullanarak hata noktasında istisnaların tetiklenmesine izin verir ve nesnenin serbest bırakıldığından emin olursunuz.

OpenPort1 yönteminde, ISerializable nesnesi SerialPort'u açma çağrısı veya SomeMethod çağrısı başarısız olabilir. Bu uygulama üzerinde bir CA2000 uyarısı verilir.

OpenPort2 yönteminde iki SerialPort nesnesi bildirilir ve null olarak ayarlanır:

  • tempPort, yöntem işlemlerinin başarılı olup olmadığını test etmek için kullanılır.

  • port, yönteminin dönüş değeri için kullanılır.

tempPort oluşturulur ve try bloğunda açılır, ve gerekli diğer tüm işler aynı try bloğunda gerçekleştirilir. Bloğun try sonunda, açılan bağlantı noktası döndürülecek port nesnesine atanır ve tempPort nesnesi null olarak ayarlanır.

finally bloğu tempPort değerini denetler. Null değilse, yöntemdeki bir işlem başarısız olmuştur ve tempPort tüm kaynakların serbest bırakıldığından emin olmak için kapatılır. Döndürülen bağlantı noktası nesnesi, yöntemin işlemleri başarılı olursa açık SerialPort nesnesini içerir veya bir işlem başarısız olursa null olur.

public SerialPort OpenPort1(string portName)
{
   SerialPort port = new SerialPort(portName);
   port.Open();  //CA2000 fires because this might throw
   SomeMethod(); //Other method operations can fail
   return port;
}

public SerialPort OpenPort2(string portName)
{
   SerialPort tempPort = null;
   SerialPort port = null;
   try
   {
      tempPort = new SerialPort(portName);
      tempPort.Open();
      SomeMethod();
      //Add any other methods above this line
      port = tempPort;
      tempPort = null;

   }
   finally
   {
      if (tempPort != null)
      {
         tempPort.Close();
      }
   }
   return port;
}
Public Function OpenPort1(ByVal PortName As String) As SerialPort

   Dim port As New SerialPort(PortName)
   port.Open()    'CA2000 fires because this might throw
   SomeMethod()   'Other method operations can fail
   Return port

End Function

Public Function OpenPort2(ByVal PortName As String) As SerialPort

   Dim tempPort As SerialPort = Nothing
   Dim port As SerialPort = Nothing

   Try
      tempPort = New SerialPort(PortName)
      tempPort.Open()
      SomeMethod()
      'Add any other methods above this line
      port = tempPort
      tempPort = Nothing

   Finally
      If Not tempPort Is Nothing Then
         tempPort.Close()
      End If

   End Try

   Return port

End Function

Örnek 2

Varsayılan olarak, Visual Basic derleyicisi tüm aritmetik işleçlerde taşma olup olmadığını kontrol eder. Bu nedenle, Visual Basic'teki herhangi bir aritmetik işlem bir OverflowException atabilir. Bu durum CA2000 gibi kurallarda beklenmeyen ihlallere yol açabilir. Örneğin, aşağıdaki CreateReader1 işlevi bir CA2000 ihlali oluşturur çünkü Visual Basic derleyicisi, StreamReader'ın atılmamasına neden olabilecek bir özel durum oluşturabilecek ekleme için bir taşma denetimi yönergesi yayar.

Bunu düzeltmek için, projenizdeki Visual Basic derleyicisi tarafından taşma denetimlerini işleme alma işlemini devre dışı bırakabilir veya kodunuzu aşağıda verilen CreateReader2 işlevi örneğindekine benzer şekilde değiştirebilirsiniz.

Taşma denetimlerinin oluşturulmasını devre dışı bırakmak için Çözüm Gezgini'nde proje adına sağ tıklayın ve Özellikler'i seçin. Gelişmiş Derleme Seçeneklerini Derle'yi>seçin ve ardından Tamsayı taşma denetimlerini kaldır'ı işaretleyin.

Imports System.IO

Class CA2000
    Public Function CreateReader1(ByVal x As Integer) As StreamReader
        Dim local As New StreamReader("C:\Temp.txt")
        x += 1
        Return local
    End Function


    Public Function CreateReader2(ByVal x As Integer) As StreamReader
        Dim local As StreamReader = Nothing
        Dim localTemp As StreamReader = Nothing
        Try
            localTemp = New StreamReader("C:\Temp.txt")
            x += 1
            local = localTemp
            localTemp = Nothing
        Finally
            If (Not (localTemp Is Nothing)) Then
                localTemp.Dispose()
            End If
        End Try
        Return local
    End Function
End Class

Ayrıca bkz.