ReSharper / C # 'da "Temsilci çıkarma işleminin öngörülemeyen sonucu var"?


124

Kullanırken myDelegate -= eventHandlerReSharper (sürüm 6) sorunları:

Temsilci çıkarma işleminin tahmin edilemeyen sonucu var

Bunun arkasındaki mantık JetBrains tarafından burada açıklanmaktadır . Açıklama mantıklı ve okuduktan sonra -delegeler üzerindeki tüm kullanımımdan şüphe duyuyorum .

Nasıl o zaman ,

  • ReSharper'ı huysuzlaştırmadan otomatik olmayan bir olay yazabilir miyim?
  • veya bunu uygulamanın daha iyi ve / veya "doğru" bir yolu var mı?
  • veya ReSharper'ı yok sayabilir miyim?

İşte basitleştirilmiş kod:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

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

Mono aynı uyarıyı verir. İşte R # sorununun açıklaması confluence.jetbrains.com/display/ReSharper/… (sadece delege listeleri için geçerlidir)
thoredge

Yanıtlar:


134

Korkmayın! ReSharper'ın uyarısının ilk bölümü yalnızca delege listelerinin kaldırılması için geçerlidir. Kodunuzda, her zaman tek bir temsilciyi kaldırıyorsunuz. İkinci bölümde, yinelenen bir delege kaldırıldıktan sonra delegelerin sıralanması anlatılmaktadır. Bir etkinlik, aboneleri için bir yürütme emrini garanti etmez, bu yüzden sizi de gerçekten etkilemez.

Yukarıdaki mekanikler öngörülemeyen sonuçlara yol açabileceğinden, ReSharper bir delege çıkarma operatörü ile karşılaştığında bir uyarı verir.

ReSharper bu uyarıyı yayınlıyor çünkü çok noktaya yayın delege çıkarma işleminde sorun olabilir, bu dil özelliğini tamamen kınamıyor. Şans eseri, bu sorunların dışında kalan durumlar vardır ve sadece basit olayları düzenlerseniz, onlarla karşılaşmanız pek olası değildir. Kendi add/ removeişleyicilerinizi uygulamanın daha iyi bir yolu yoktur , sadece dikkat etmeniz gerekir.

ReSharper'ın bu mesaj için uyarı düzeyini "İpucu" olarak düşürmenizi öneririm, böylece genellikle yararlı olan uyarılarına duyarsızlaşmazsınız.


67
Sonuçları "öngörülemez" olarak adlandırmanın R # için kötü olduğunu düşünüyorum. Açıkça belirtilmişler. "Kullanıcının tahmin edebileceği şey değil", "tahmin edilemez" ile hiçbir şekilde aynı şey değildir. (. Bu NET framework tanımlar aşırı yüklenmeler olduğunu söylemek de yanlış - bu C # derleyicisi içine yapışmış Delegateyok değil aşırı +ve -.)
Jon Skeet

6
@Jon: Katılıyorum. Sanırım herkes Microsoft'un kendisi için belirlediği yüksek çıta alıştı. NET dünyasında "başarı çukuruna" düşmenize neden olan pek çok şey olduğu kadar, lehçe seviyesinin olduğu kadar yüksek olması, çukurun yanında sadece hızlı bir yürüyüş olan bir dil özelliğiyle karşılaşmanız Muhtemelen kaçırabilirsiniz, bazıları tarafından sarsıcı olarak kabul edilir ve bir işaretin söylenmesini gerektirir PIT OF SUCCESS IS THAT WAY --->.
Allon Guralnek

5
@AllonGuralnek: Öte yandan, en son ne zaman birinin bu nedenle gerçekten bir sorun yaşadığını duydunuz?
Jon Skeet

5
@Jon: Bununla ilgili bir sorun mu duydunuz? Bu soru gönderilmeden önce bu davranışı bilmiyordum bile .
Allon Guralnek

2
R # 'nın delege çıkarma konusunda uyarması, ancak aynı sorunu olan olayların ortak uygulamaları konusunda uyarmaması ilginçtir . Temel sorun, Delegate.Combine.net'in çok noktaya yayın delegelerini "düzleştiren" bir tek kullanmasıdır , bu nedenle delegeler [X, Y] ve Z verilirse, sonucun [X, Y, Z] veya [[ X, Y], Z] ( [X,Y]delegeyi kendi olarak tutan ikinci delege Targetve bu delegenin Invokeyöntemini onun olarak tutar Method).
supercat

28

Temsilcileri toplamak veya çıkarmak için doğrudan kullanmamalısınız. Senin alanın yerine

MyHandler _myEvent;

Bunun yerine bir olay olarak da ilan edilmelidir. Bu, çözümünüzü riske atmadan sorunu çözecek ve yine de olay kullanımının avantajına sahip olacaktır.

event MyHandler _myEvent;

Temsilci toplamının veya çıkarma işleminin kullanılması tehlikelidir çünkü yalnızca temsilciyi atarken olayları kaybedebilirsiniz (bildirime göre, geliştirici bunun bir olay olarak bildirildiği zaman olduğu gibi bunun bir Çok Noktaya Yayın temsilcisi olduğu sonucuna doğrudan varmayacaktır). Örnek vermek gerekirse, bu soruda bahsedilen özellik bir olay olarak işaretlenmediyse, aşağıdaki kod ilk iki atamanın KAYIP olmasını isteyecektir, çünkü birisi sadece temsilciye atanmıştır (ki bu da geçerlidir!).

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

Method3'ü atarken, ilk iki aboneliği tamamen kaybettim. Olay kullanımı bu sorunu önleyecek ve aynı zamanda ReSharper uyarısını kaldıracaktır.


Bunu bu şekilde yapmayı hiç düşünmemiştim, ancak temeldeki olayı gizli tuttuğunuz sürece olay delege kullanımını korumak mantıklı geliyor. Ancak bu, birden çok olay aboneliği veya izlenmesi gereken alt abonelikler gibi ekle / kaldır işleyicilerinde olması gereken daha spesifik iş parçacığı senkronizasyonu olduğunda iyi çalışmaz. Ancak her durumda uyarıları kaldırır.
Jeremy

-17

- = kullanmak yerine = null olarak ayarlayın


5
removebir olayın yöntemi tüm işleyicileri kaldırmaz, daha ziyade talep edildi işleyicisi kaldırılacak.
2015 17

eğer sadece bir tane eklerse, o zaman sadece birini kaldırırsa, hepsini kaldırır. Her durumda, yalnızca bu özel yeniden paylaşım mesajı için kullanın demiyorum.
Jonathan Beresford

6
Ama yok temsilci her zaman çağırma listesindeki tek öğe kaldırdığını biliyoruz. Bu, doğru çalışma kodunu, bazı durumlarda tesadüfen işe yarayacak, ancak çoğu durumda olağandışı ve teşhis edilmesi zor yollardan çıkacak hatalı kırılmış koda dönüştürerek yeniden paylaşma mesajını ortadan kaldırıyor.
Servy

Buna ek oy vermek zorunda kaldım çünkü -17, "potansiyel" bir cevap yazmak için zaman ayıran biri için çok sert bir ceza. Hatalı olsanız bile pasif olmadığınız için +1.
John C
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.