Mengapa menggunakan try {} akhirnya {} dengan blok try kosong?

239

Saya perhatikan dalam System.Threading.TimerBase.Dispose()metode ini memiliki try{} finally{}blok tetapi try{}kosong.

Apakah ada nilai dalam menggunakan try{} finally{}dengan kosong try?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try {
    }
    finally {
        do {
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
                bLockTaken = true;
                try {
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                }
                finally {
                    m_lock = 0;
                }
            }
            Thread.SpinWait(1);
            // yield to processor
        }
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    }

    return status;
}
Samuel Neff
sumber
System.Diagnostics.Proses di sekitar jalur 2144 juga: Referenceource.microsoft.com/#System/services/monitoring/…
Patrick Artner

Jawaban:

171

Dari http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/ :

Metodologi ini melindungi terhadap panggilan Thread.Abort yang mengganggu pemrosesan. Halaman MSDN dari Thread.Abort mengatakan bahwa "Blok akhirnya dieksekusi dieksekusi sebelum utas dibatalkan". Jadi untuk menjamin bahwa proses Anda selesai bahkan jika utas Anda dibatalkan di tengah oleh seseorang yang memanggil Abort di utas Anda, Anda dapat menempatkan semua kode Anda di blok akhirnya (alternatifnya adalah menulis kode di blok "catch" ke tentukan di mana Anda berada sebelum "coba" terganggu oleh Abort dan lanjutkan dari sana jika Anda mau).

danben
sumber
6
Mengapa tidak menggunakan msdn.microsoft.com/en-us/library/… ?
Rob Fonseca-Ensor
15
Karena itu tidak tersedia sampai. NET 2.0
Hans Passant
6
@ RobFonseca-Ensor: Karena Thread.BeginCriticalRegion()tidak mencegah utas dibatalkan, lebih baik memberitahukan runtime bahwa jika utas dibatalkan, maka negara global rusak, dan seluruh appdomain terserah pembunuhan rahmat.
kkm
9
@HansPassant: BeginCriticalSection()benar-benar tidak ada di .NET 1.x, tetapi tidak ada sebab dan akibat, yang Anda maksudkan karena . Bahkan, dalam. NET 1.x, bahkan satu finallyblok bisa saja terganggu oleh ulir yang dibatalkan. Mekanisme-mekanisme ini memiliki tujuan yang berbeda: melakukan pekerjaan dalam finallymencegah aborsi di tengah jalan dalam kode, sementara BeginCriticalSection()hanya menyatakan kepada runtime bahwa negara global dalam bahaya.
kkm
Jika pengembang memiliki waktu (benar) pada akhirnya akankah aborsi selesai atau bisakah aborsi secara teknis diabaikan tanpa batas waktu?
Max Young
64

Ini untuk menjaga agar tidak Thread.Abortmengganggu proses. Dokumentasi untuk metode ini mengatakan bahwa:

Blok yang tidak dieksekusi akhirnya dieksekusi sebelum utas dibatalkan.

Ini karena untuk berhasil memulihkan dari kesalahan, kode Anda harus dibersihkan sendiri. Karena C # tidak memiliki destruktor gaya C ++, finallydan usingblok adalah satu-satunya cara yang dapat diandalkan untuk memastikan bahwa pembersihan tersebut dilakukan dengan andal. Ingat bahwa usingblok berubah menjadi ini oleh kompiler:

try {
    ...
}
finally {
    if(obj != null)
        ((IDisposable)obj).Dispose();
}

Di .NET 1.x, ada kemungkinan finallyblok akan dibatalkan. Perilaku ini diubah dalam .NET 2.0.

Selain itu, tryblok kosong tidak pernah dioptimalkan oleh kompiler.

Anton Gogolev
sumber
Terima kasih atas wawasan tentang blok penggunaan.
Stefan
@ Anton Saya mengerti bahwa menggunakan adalah praktik terbaik. Tetapi untuk tujuan mengejek, kadang-kadang kelas pembungkus perlu diimplementasikan dan objek sekali pakai menjadi variabel kelas pribadi. Jika kita membuat pembungkus ini sekali pakai, bukankah GC menangani pembuangan variabel kelas privat secara otomatis?
Ozkan
@ Ozkan, GC tidak membuang apa pun secara otomatis. Anda perlu menerapkan finalizer, biasanya memanggil aDispose(false); . docs.microsoft.com/en-us/dotnet/standard/garbage-collection/…
Thorarin
@Torarin maaf tapi Anda salah dengan mengatakan GC tidak membuang (menyelesaikan) secara otomatis.
Ozkan