Özel durumlar için en iyi yöntemler

İyi tasarlanmış bir uygulama, özel durumları ve hataları işleyerek uygulama kilitlenmelerini önler. Bu bölümde özel durumları işlemeye ve oluşturmaya yönelik en iyi yöntemler açıkmaktadır.

Hatalardan veya yayın kaynaklarından kurtarmak için try/catch/finally bloklarını kullanma

Kod try / catch çevresinde özel durum oluşturabilecek blokları kullanın ve kodunuz bu özel durumdan kurtarılabilir. catchBloklarda, özel durumları her zaman en fazla türetilenden en az türetilene sırala. Tüm özel durumlar ' den Exception türetildi. Daha fazla türetilmiş özel durum, temel bir özel durum sınıfı için bir catch yan tümcesinden önce gelen bir catch yan tümcesi tarafından işlanmaz. Kodunuz bir özel durumdan kurtarılamazsa, bu özel durumu yakalamayın. Mümkünse kurtarmak için yöntemleri çağrı yığınını daha da fazla etkinleştirin.

Deyimler veya bloklarla using ayrılmış kaynakları finally temizleyin. Özel using durumlar are thrown olduğunda kaynakları otomatik olarak temizlemek için deyimlerini tercih eder. Uygulamasız finally kaynakları temizlemek için blokları IDisposable kullanın. Bir yan finally tümcesi içinde kod, özel durumlar olduğunda bile neredeyse her zaman yürütülür.

Özel durumlar olmadan genel koşulları işleme

Oluşma olasılığı yüksek ancak bir özel durum tetikleyecek koşullar için, bunları özel durumdan kaçınacak şekilde işlemeyi göz önünde bulundurarak. Örneğin, zaten kapatılmış bir bağlantıyı kapatmayı denersiniz, bir elde InvalidOperationException edin. Kapatmaya çalışmadan önce bağlantı if durumunu kontrol etmek için deyimini kullanarak bundan kaçınabilirsiniz.

if (conn->State != ConnectionState::Closed)
{
    conn->Close();
}
if (conn.State != ConnectionState.Closed)
{
    conn.Close();
}
If conn.State <> ConnectionState.Closed Then
    conn.Close()
End IF

Kapatmadan önce bağlantı durumunu denetlemezsiniz, özel durumu InvalidOperationException yakalayabilirsiniz.

try
{
    conn->Close();
}
catch (InvalidOperationException^ ex)
{
    Console::WriteLine(ex->GetType()->FullName);
    Console::WriteLine(ex->Message);
}
try
{
    conn.Close();
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.GetType().FullName);
    Console.WriteLine(ex.Message);
}
Try
    conn.Close()
Catch ex As InvalidOperationException
    Console.WriteLine(ex.GetType().FullName)
    Console.WriteLine(ex.Message)
End Try

Seçecek yöntem, olayın ne sıklıkta gerçekleşmesini beklediğinize bağlıdır.

  • Olay çok sık oluşmuyorsa, yani gerçekten olağanüstüyse ve bir hatayı gösteriyorsa (beklenmeyen bir dosya sonu gibi), özel durum işlemeyi kullanın. Özel durum işleme kullandığınızda, normal koşullarda daha az kod çalıştırılır.

  • Olay düzenli olarak gerçekleşirse ve normal yürütmenin parçası olarak kabul edilirse kodda hata koşullarını kontrol edin. Sık karşılaşılan hata koşullarını kontrol edin, özel durumlardan kaçınarak daha az kod yürütülür.

Özel durumlardan kaçınılması için sınıfları tasarlama

Bir sınıf, özel durum tetikleyen bir çağrı yapmaktan kaçınmanız için yöntemler veya özellikler sağlar. Örneğin, bir FileStream sınıfı dosyanın sonuna ulaşıp ulaşı olmadığını belirlemeye yardımcı olan yöntemler sağlar. Bunlar, dosyanın sonunu okuduğunda, özel durumu önlemek için kullanılabilir. Aşağıdaki örnek, bir özel durum tetiklemeden bir dosyanın sonuna kadar okumayı gösterir.

class FileRead
{
public:
    void ReadAll(FileStream^ fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == nullptr)
        {
            throw gcnew System::ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead->Seek(0, SeekOrigin::Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead->Length; i++)
        {
            b = fileToRead->ReadByte();
            Console::Write(b.ToString());
            // Or do something else with the byte.
        }
    }
};
class FileRead
{
    public void ReadAll(FileStream fileToRead)
    {
        // This if statement is optional
        // as it is very unlikely that
        // the stream would ever be null.
        if (fileToRead == null)
        {
            throw new ArgumentNullException();
        }

        int b;

        // Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin);

        // Read each byte to the end of the file.
        for (int i = 0; i < fileToRead.Length; i++)
        {
            b = fileToRead.ReadByte();
            Console.Write(b.ToString());
            // Or do something else with the byte.
        }
    }
}
Class FileRead
    Public Sub ReadAll(fileToRead As FileStream)
        ' This if statement is optional
        ' as it is very unlikely that
        ' the stream would ever be null.
        If fileToRead Is Nothing Then
            Throw New System.ArgumentNullException()
        End If

        Dim b As Integer

        ' Set the stream position to the beginning of the file.
        fileToRead.Seek(0, SeekOrigin.Begin)

        ' Read each byte to the end of the file.
        For i As Integer = 0 To fileToRead.Length - 1
            b = fileToRead.ReadByte()
            Console.Write(b.ToString())
            ' Or do something else with the byte.
        Next i
    End Sub
End Class

Özel durumlardan kaçınmanın bir diğer yolu, özel durum atmak yerine son derece yaygın hata durumları için null (veya varsayılan) dönmektir. Çok yaygın olan bir hata durumu, denetiminin normal akışı olarak kabul edilebilir. Bu durumlarda null (veya varsayılan) döndürerek, bir uygulamanın performans etkisini en aza indirmiş oluruz.

Değer türleri için, hata göstergeniz olarak kullanmak veya varsayılan yapmak, belirli bir Nullable<T> uygulama için göz önünde bulunduracak bir değerdir. kullanılarak Nullable<Guid> yerine default null Guid.Empty olur. Bazı durumlarda, ekleme bir değerin mevcut veya eksik Nullable<T> olduğu daha net hale neden olabilir. Diğer durumlarda, ekleme gerekli olmayanları kontrol etmek için ek durumlar oluşturabilir ve Nullable<T> yalnızca olası hata kaynakları oluşturmak için hizmet eder.

Hata kodu dönmek yerine özel durumlar oluşturur

Özel durumlar, kod çağırma bir dönüş kodunu denetlemeytiği için hataların farkedimemelerini sağlar.

Önceden tanımlanmış .NET özel durum türlerini kullanma

Yalnızca önceden tanımlanmış bir özel durum sınıfı geçerli değilken yeni bir özel durum sınıfı tanıtma. Örnek:

  • Nesnenin InvalidOperationException geçerli durumuna göre bir özellik kümesi veya yöntem çağrısı uygun yoksa bir özel durum oluşturur.

  • Geçersiz parametreler ArgumentException geçir edilirse, bir özel durum veya 'den ArgumentException türeten önceden tanımlanmış sınıflardan birini oluşturur.

End exception class names with the word Exception

Özel bir özel durum gerekli olduğunda, uygun şekilde ad ve sınıfından Exception türet. Örnek:

public ref class MyFileNotFoundException : public Exception
{
};
public class MyFileNotFoundException : Exception
{
}
Public Class MyFileNotFoundException
    Inherits Exception
End Class

Özel özel durum sınıflarında üç oluşturucu dahil

Kendi özel durum sınıflarınızı oluştururken en az üç ortak oluşturucu kullanın: parametresiz oluşturucu, dize iletisi alan bir oluşturucu ve bir dize iletisi ve iç özel durum alan bir oluşturucu.

Bir örnek için, bkz. How to: Create User-Defined Exceptions.

Kod uzaktan yürütülürken özel durum verilerinin kullanılabilir olduğundan emin olmak

Kullanıcı tanımlı özel durumlar oluştururken, özel durumlar için meta verilerin uzaktan yürütülen kod için kullanılabilir olduğundan emin olur.

Örneğin, Uygulama Etki Alanlarını destekleyen .NET uygulamaları üzerinde, Uygulama etki alanlarında özel durumlar oluşabilir. Uygulama Etki Alanı A'nın özel durum oluşturan kodu yürüten Uygulama Etki Alanı B oluşturduğu düşünün. Uygulama Etki Alanı A'nın özel durumu düzgün bir şekilde yakalaması ve işlemesi için, Uygulama Etki Alanı B tarafından atılan özel durumu içeren derlemeyi bulabilecek olmalıdır. Uygulama Etki Alanı B, uygulama tabanı altındaki bir derlemede yer alan ancak Uygulama Etki Alanı A'nın uygulama tabanı altında yer alan bir özel durum oluşturursa, Uygulama Etki Alanı A özel durumu bulamaz ve ortak dil çalışma zamanı bir özel durum FileNotFoundException oluşturur. Bu durumu önlemek için, özel durum bilgisini içeren derlemeyi iki şekilde dağıtabilirsiniz:

  • Derlemeyi iki uygulama etki alanı tarafından paylaşılan ortak bir uygulama temel dizinine koyun.

    - veya -

  • Eğer etki alanları ortak bir uygulama temel dizini paylaşmıyorsa, özel durum bilgisi içeren derlemeyi bir tanımlayıcı ad ile imzalayıp derlemeyi genel bütünleştirilmiş kod önbelleğine dağıtarak.

Dilbilgisiyle doğru hata iletilerini kullanma

Net cümleler yazın ve bitiş noktalama işaretlerini dahil etmek. Özelliğine atanan dizede yer alan Exception.Message her cümle bir noktayla bitebildi. Örneğin, "Günlük tablosu taştı." , uygun bir ileti dizesi olacaktır.

Her özel durum için yerelleştirilmiş dize iletisi dahil

Kullanıcının gördüğü hata iletisi, özel durum sınıfının adı değil, atılan özel Exception.Message durumun özelliğinden türetildi. Genellikle, bir Özel durum oluşturucusuz Exception.Message bağımsız değişkenine ileti dizesini message geçerek özelliğine bir değer atarsınız.

Yerelleştirilmiş uygulamalar için, uygulamanıza atılan her özel durum için yerelleştirilmiş bir ileti dizesi sağlayabilirsiniz. Yerelleştirilmiş hata iletileri sağlamak için kaynak dosyalarını kullanırsınız. Uygulamaları yerelleştirme ve yerelleştirilmiş dizeleri alma hakkında bilgi için aşağıdaki makalelere bakın:

Özel özel durumlarda, gerektiğinde ek özellikler sağlama

Yalnızca ek bilgilerin yararlı olduğu programlı bir senaryo olduğunda bir özel durum için ek özellikler (özel ileti dizesine ek olarak) sağlama. Örneğin, FileNotFoundException özelliğini FileName sağlar.

Yığın izlemenin yararlı olması için throw deyimlerini yer

Yığın izlemesi, özel durumun atılmış olduğu deyimde başlar ve özel durumu catch yakalayacak deyiminde sona erer.

Özel durum oluşturucu yöntemlerini kullanma

Bir sınıfın uygulamasında aynı özel durumu farklı yerlerde oluşturması yaygındır. Fazla kodu önlemek için, özel durumu oluşturmak ve döndürmek için yardımcı yöntemler kullanın. Örnek:

ref class FileReader
{
private:
    String^ fileName;

public:
    FileReader(String^ path)
    {
        fileName = path;
    }

    array<Byte>^ Read(int bytes)
    {
        array<Byte>^ results = FileUtils::ReadFromFile(fileName, bytes);
        if (results == nullptr)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException^ NewFileIOException()
    {
        String^ description = "My NewFileIOException Description";

        return gcnew FileReaderException(description);
    }
};
class FileReader
{
    private string fileName;

    public FileReader(string path)
    {
        fileName = path;
    }

    public byte[] Read(int bytes)
    {
        byte[] results = FileUtils.ReadFromFile(fileName, bytes);
        if (results == null)
        {
            throw NewFileIOException();
        }
        return results;
    }

    FileReaderException NewFileIOException()
    {
        string description = "My NewFileIOException Description";

        return new FileReaderException(description);
    }
}
Class FileReader
    Private fileName As String


    Public Sub New(path As String)
        fileName = path
    End Sub

    Public Function Read(bytes As Integer) As Byte()
        Dim results() As Byte = FileUtils.ReadFromFile(fileName, bytes)
        If results Is Nothing
            Throw NewFileIOException()
        End If
        Return results
    End Function

    Function NewFileIOException() As FileReaderException
        Dim description As String = "My NewFileIOException Description"

        Return New FileReaderException(description)
    End Function
End Class

Bazı durumlarda, özel durumu derlemek için özel durumun oluşturucusu kullanmak daha uygundur. Örneğin, gibi bir genel özel durum ArgumentException sınıfıdır.

Yöntemler özel durumlar nedeniyle tamamlanmadıkları zaman geri yükleme durumu

Bir yöntemi çağıranlar, bu yöntemde özel durum oluşturulduğunda bunun yan etkileri olmayacağını varsayabilmelidir. Örneğin, bir hesaptan çekerek ve başka bir hesaba para aktararak para aktaran kodunuz varsa ve para ödemesini yürütürken bir özel durum varsa, devam etmek istemeyebilirsiniz.

public void TransferFunds(Account from, Account to, decimal amount)
{
    from.Withdrawal(amount);
    // If the deposit fails, the withdrawal shouldn't remain in effect.
    to.Deposit(amount);
}
Public Sub TransferFunds(from As Account, [to] As Account, amount As Decimal)
    from.Withdrawal(amount)
    ' If the deposit fails, the withdrawal shouldn't remain in effect.
    [to].Deposit(amount)
End Sub

Yukarıdaki yöntem doğrudan herhangi bir özel durum oluşturur, ancak savunmaya yazarak, para çekme işlemi başarısız olursa ters çevrilebilir.

Bu durumu işlemenin bir yolu, para çekme işlemi tarafından atılan özel durumları yakalamak ve geri almaktır.

private static void TransferFunds(Account from, Account to, decimal amount)
{
    string withdrawalTrxID = from.Withdrawal(amount);
    try
    {
        to.Deposit(amount);
    }
    catch
    {
        from.RollbackTransaction(withdrawalTrxID);
        throw;
    }
}
Private Shared Sub TransferFunds(from As Account, [to] As Account, amount As Decimal)
    Dim withdrawalTrxID As String = from.Withdrawal(amount)
    Try
        [to].Deposit(amount)
    Catch
        from.RollbackTransaction(withdrawalTrxID)
        Throw
    End Try
End Sub

Bu örnek, özelliğini incelemek zorunda kalmadan çağıranların sorunun gerçek nedenini görmelerini kolaylaştıran özgün özel durumu yeniden atmak throw için kullanımını InnerException göstermektedir. Alternatif olarak, yeni bir özel durum oluşturur ve özgün özel durumu iç özel durum olarak dahil etmektir:

catch (Exception ex)
{
    from.RollbackTransaction(withdrawalTrxID);
    throw new TransferFundsException("Withdrawal failed.", innerException: ex)
    {
        From = from,
        To = to,
        Amount = amount
    };
}
Catch ex As Exception
    from.RollbackTransaction(withdrawalTrxID)
    Throw New TransferFundsException("Withdrawal failed.", innerException:=ex) With
    {
        .From = from,
        .[To] = [to],
        .Amount = amount
    }
End Try

Ayrıca bkz.