"Pengurangan delegasi memiliki hasil yang tidak dapat diprediksi" di ReSharper / C #?

124

Saat menggunakan masalah myDelegate -= eventHandlerReSharper (versi 6):

Pengurangan delegasi memiliki hasil yang tidak dapat diprediksi

Alasan di balik ini dijelaskan oleh JetBrains di sini . Penjelasannya masuk akal dan, setelah membacanya, saya meragukan semua kegunaan saya -pada delegasi.

Lalu bagaimana ,

  • dapatkah saya menulis acara non-otomatis tanpa membuat ReSharper marah?
  • atau, apakah ada cara yang lebih baik dan / atau "benar" untuk menerapkan ini?
  • atau, bisakah saya mengabaikan ReSharper?

Berikut kode yang disederhanakan:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

public event MyHandler MyEvent
{
    add
    {
        _myEvent += value;
        DoSomethingElse();
    }
    remove
    {
        _myEvent -= value; // <-- ReSharper warning here
    }
}

sumber
Mono memberikan peringatan yang sama. Berikut adalah deskripsi R # tentang masalah confluence.jetbrains.com/display/ReSharper/… (yang hanya berlaku untuk daftar delegasi)
thoredge

Jawaban:

134

Jangan takut! Bagian pertama dari peringatan ReSharper hanya berlaku untuk menghapus daftar delegasi. Dalam kode Anda, Anda selalu menghapus satu delegasi. Bagian kedua berbicara tentang pemesanan delegasi setelah delegasi duplikat dihapus. Peristiwa tidak menjamin urutan eksekusi untuk pelanggannya, sehingga tidak terlalu memengaruhi Anda.

Karena mekanisme di atas dapat menyebabkan hasil yang tidak dapat diprediksi, ReSharper mengeluarkan peringatan setiap kali menemui operator pengurangan delegasi.

ReSharper mengeluarkan peringatan ini karena pengurangan delegasi multicast dapat berakibat fatal, itu tidak mengutuk fitur bahasa itu sepenuhnya. Untungnya gotcha itu ada dalam kasus pinggiran dan Anda tidak mungkin menemukannya jika Anda hanya memperagakan acara sederhana. Tidak ada cara yang lebih baik untuk menerapkan add/ removepenangan Anda sendiri , Anda hanya perlu memperhatikan.

Saya menyarankan untuk menurunkan tingkat peringatan ReSharper untuk pesan itu menjadi "Petunjuk" sehingga Anda tidak peka terhadap peringatan mereka, yang biasanya berguna.

Allon Guralnek
sumber
66
Saya pikir itu buruk R # untuk menyebut hasil "tidak dapat diprediksi". Mereka ditentukan dengan sangat jelas. "Bukan yang mungkin diprediksi pengguna" sama sekali tidak sama dengan "tidak dapat diprediksi". (Ini juga tidak akurat untuk mengatakan bahwa NET framework mendefinisikan overloads -. Itu dipanggang ke dalam C # compiler Delegatetidak tidak membebani +dan -.)
Jon Skeet
6
@ Jon: Saya setuju. Saya kira semua orang terbiasa dengan standar tinggi yang ditetapkan Microsoft untuk dirinya sendiri. Tingkat pemolesan menjadi setinggi itu, dengan begitu banyak hal di dunia .NET yang membuat Anda "jatuh ke lubang kesuksesan", menemukan fitur bahasa yang hanya berjalan cepat di samping lubang di mana ada kemungkinan Anda melewatkannya, itu dianggap oleh beberapa orang sebagai menggelegar dan membutuhkan tanda yang bertuliskan PIT OF SUCCESS IS THAT WAY --->.
Allon Guralnek
5
@AllonGuralnek: Di sisi lain, kapan terakhir kali Anda mendengar seseorang benar-benar mengalami masalah karena ini?
Jon Skeet
5
@ Jon: Pernah dengar ada masalah dengan itu? Saya bahkan tidak tahu tentang perilaku ini sebelum pertanyaan ini diposting.
Allon Guralnek
2
Sangat mengherankan bahwa R # akan memperingatkan tentang pengurangan delegasi, tetapi tidak memperingatkan tentang implementasi umum peristiwa yang memiliki masalah yang sama persis . Masalah utamanya adalah bahwa .net menggunakan sebuah single Delegate.Combineyang "mendatar" delegasi multicast, jadi jika diberikan delegasi [X, Y] dan Z, tidak dapat membedakan apakah hasilnya harus [X, Y, Z] atau [[ X, Y], Z] (delegasi terakhir memegang [X,Y]delegasi sebagai miliknya Target, dan Invokemetode delegasi itu sebagai miliknya Method).
supercat
28

Anda tidak boleh secara langsung menggunakan delegasi untuk menjumlahkan atau mengurangi. Sebaliknya bidang Anda

MyHandler _myEvent;

Sebaliknya harus dinyatakan sebagai acara juga. Ini akan menyelesaikan masalah tanpa mempertaruhkan solusi Anda dan masih memiliki manfaat penggunaan acara.

event MyHandler _myEvent;

Penggunaan jumlah atau pengurangan delegasi berbahaya karena Anda bisa kehilangan peristiwa ketika hanya menetapkan delegasi (sesuai deklarasi, pengembang tidak akan langsung menyimpulkan ini adalah delegasi Multicast seperti ketika dideklarasikan sebagai peristiwa). Sebagai contoh, jika properti yang disebutkan pada pertanyaan ini tidak ditandai sebagai peristiwa, kode di bawah ini akan membuat dua tugas pertama menjadi HILANG, karena seseorang hanya ditugaskan ke delegasi (yang juga valid!).

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;

Saat menetapkan Method3, saya benar-benar kehilangan dua langganan awal. Penggunaan acara akan menghindari masalah ini dan pada saat yang sama menghapus peringatan ReSharper.

blimac.dll
sumber
Saya tidak pernah berpikir untuk melakukannya dengan cara ini, tetapi masuk akal untuk melindungi penggunaan delegasi acara selama Anda tetap merahasiakan acara yang mendasarinya. Namun ini tidak berfungsi dengan baik ketika ada sinkronisasi utas yang lebih spesifik yang harus terjadi di penangan tambah / hapus seperti beberapa langganan acara atau sub-langganan yang perlu dilacak juga. Namun, bagaimanapun, itu menghapus peringatan.
Jeremy
-17

setel ke = null daripada menggunakan - =

Jonathan Beresford
sumber
5
yang removemetode dari suatu peristiwa tidak harus menghapus semua penangan, melainkan handler yang diminta untuk dihapus.
Pelayanan
jika dia hanya menambahkan satu maka jika dia hanya menghapus satu efek, dia telah menghapus semuanya. Saya tidak mengatakan menggunakannya dalam semua kasus hanya untuk pesan resharper khusus ini.
Jonathan Beresford
6
Namun Anda tidak tahu bahwa delegasi selalu menghapus satu-satunya item di daftar pemanggilan. Ini membuat pesan resharper hilang dengan mengubah kode yang berfungsi dengan benar menjadi kode rusak yang salah yang akan, dalam keadaan tertentu, secara tidak sengaja berfungsi, tetapi akan rusak dengan cara yang tidak biasa dan sulit untuk didiagnosis dalam banyak kasus.
Pelayanan
Saya harus mendukung ini karena -17 adalah hukuman yang terlalu keras bagi seseorang yang meluangkan waktu untuk menulis jawaban "potensial". 1 karena tidak pasif, meskipun Anda salah.
John C