Sihirli yöntemler neden C # 'da uygulandı?


16

C # 'da, tüm bu sihirli yöntemlerin bir arayüz tarafından yedeklenmeden ortaya çıktığını görmeye başladım. Bu neden seçildi?

Açıklamama izin ver.

Daha önce C # 'da, bir nesne IEnumerablearayüzü uyguladıysa, otomatik olarak bir foreachdöngü tarafından tekrarlanabilirdi. Bu benim için bir anlam ifade ediyor, çünkü bir arayüz tarafından destekleniyor ve eğer Iteratoryinelenen sınıfın içinde kendi işlevime sahip olsaydım, sihirli bir şekilde başka bir şey anlamına geleceğinden endişe etmeden yapabilirdim.

Şimdi, görünüşe göre, (ne zaman emin değilim), bu arayüzler artık gerekli değildir. Sadece doğru adlandırma dönüşümlerine sahip olması gerekir.

Başka bir örnek, tam olarak GetAwaiter birkaç spesifik özelliğe sahip bir yönteme sahip olarak herhangi bir nesneyi beklenebilir hale getirmektir .

Neden bu "sihir" i statik olarak destekledikleri IEnumerableveya destekleyecekleri gibi bir arayüz INotifyPropertyChangedoluşturmuyorsunuz?

Burada ne demek istediğim hakkında daha fazla bilgi:

http://blog.nem.ec/2014/01/01/magic-methods-c-sharp/

Sihirli yöntemlerin artıları ve eksileri nelerdir ve bu kararların neden verildiği hakkında herhangi bir şey bulabileceğim çevrimiçi herhangi bir yer var mı?


4
Kapatmak istemiyorsanız neden "sihir kötüdür" konusundaki kişisel görüşünüzü düzenlemelisiniz.
DougM

2
Anders Hejlsberg'in bunu neden yaptığını bilmek istiyorsanız, ona sormanız gerekecek. Size sadece bunu neden yapabileceğimi söyleyebilirim ve bu ileriye dönük uyumluluk içindir. Eklenti yöntemleri, mevcut türlere eklenti yöntemlerini "taklit etmenize" izin verir, ancak eklenti arabirimleri yoktur. Örneğin, async/ için bir arabirime ihtiyacınız varsa await, bu yalnızca .NET 4.5 uygulanabilir bir hedef olacak kadar geniş bir alana yayıldıktan sonra yazılan kodla çalışacaktır ... temel olarak şu anda. Ancak yöntem çağrılarına tamamen sözdizimsel bir çeviri await, gerçeklerden sonra mevcut türlere işlevsellik eklememe izin veriyor .
Jörg W Mittag

2
Bunun temel olarak nesne yönelimi uygulandığını unutmayın: bir nesne uygun iletilere yanıt verdiği sürece, doğru türde olduğu kabul edilir.
Jörg W Mittag

7
"Önceden" ve "şimdi" terimleriniz geri - sihirli yöntem, foreachbaşlangıçta bir döngü için temel işlev olarak uygulandı . Orada asla nesne uygulamak için bir gereklilik olmuştur IEnumerableiçin foreachişe. Bunu yapmak sadece kongre oldu.
Jesse C. Slicer

2
@gbulmer bu fikri nereden aldığımı hatırlıyorum: blogs.msdn.com/b/ericlippert/archive/2011/06/30/… (ve daha az ölçüde ericlippert.com/2013/07/22/… )
Jesse C. Slicer

Yanıtlar:


16

Genel olarak “sihirli yöntemler” aynı şekilde çalışan bir arayüz oluşturmak mümkün olmadığında kullanılır.

Ne zaman foreachilk (yani davranış kesinlikle son şey değildir) C # 1.0 başlandı hiçbir jenerik vardı çünkü, sihirli yöntemleri kullanmak zorunda kaldı. Seçenekler temel olarak:

  1. Jenerik olmayan IEnumerableve s IEnumeratorile çalışan objectboks değer türleri anlamına gelir. Bir ints listesi gibi bir şeyi yinelemek çok hızlı olmalı ve kesinlikle çok fazla çöp kutulu değer yaratmamalıdır, bu iyi bir seçim değildir.

  2. Jenerikleri bekleyin. Bu muhtemelen .Net 1.0'ın (veya en azından foreach) 3 yıldan fazla ertelenmesi anlamına gelir .

  3. Sihirli yöntemler kullanın.

Yani, # 3 seçeneğini seçtiler ve .Net 2.0'dan beri gerektiren geriye dönük uyumluluk nedenleriyle bizimle birlikte kaldılar IEnumerable<T>.


Koleksiyon başlatıcıları her koleksiyon türünde farklı görünebilir. Karşılaştır List<T>:

public void Add(T item)

ve Dictionary<TKey, TValue>:

public void Add(TKey key, TValue value)

Yalnızca ilk formunu List<T>ve yalnızca ikinci formunu destekleyecek tek bir arabiriminiz olamaz Dictionary<TKey, TValue>.


LINQ yöntemleri genellikle genişletme yöntemleri olarak uygulanır (böylece, uygulanan tüm türler için örneğin LINQ'dan Nesneye yalnızca tek bir uygulama olabilir IEnumerable<T>), yani bir arabirim kullanmak mümkün değildir.


İçin await, GetResult()yöntem herhangi voidbir tür veya bir tür döndürebilir T. Yine, her ikisini de işleyebilecek tek bir arayüze sahip olamazsınız. awaitKısmen arayüz temelli olmasına rağmen : Bekçi uygulamak zorundadır INotifyCompletionve uygulayabilir ICriticalNotifyCompletion.


1
C # 1.0 için "# 3 seçeneğini seçtiler mi?" Benim hatırlama seçenek 1 idi. Hafızam, C # derleyici 'otomatik-boks' ve 'otomatik-kutulama' yaptı çünkü Java üzerinde önemli üstünlük iddia etti. Bu iddia, C # gibi kodun kısmen bu nedenle Java daha iyi çalışması gibi kod yaptı .
gbulmer

1
foreachC # 1.2'deki belgeler (C # 1.0 için MSDN'de hiçbir şey yoktur) ifadesi foreach“Uygulayan bir türü IEnumerableveya bir GetEnumeratoryöntemi bildiren bir türü değerlendirir .” İfadesinin bu kutudan ne kastettiğinden emin değilim C # her zaman açıktır.
svick

1
@gbulmer Ve Aralık 2001'den itibaren C # için ECMA spesifikasyonu (C # 1.0 için olduğu anlamına gelir) de şunu söylüyor: (§15.8.4): “System.Inumerable arayüzünü uygularsa C tipi bir koleksiyon tipi olarak söylenir. veya aşağıdaki kriterlerin tümünü karşılayarak toplama modelini uygular […] ”.
svick

1
@svick , dizinin öğelerine foreach(T x in sequence)açık dökümler uygular T. Bu nedenle, sekans düz IEnumerableve Tdeğer tipiyse, kodunuza herhangi bir açık döküm yazılmadan kutudan çıkarılır. C #'ın daha çirkin kısımlarından biri.
CodesInChaos

@CodesInChaos "Otomatik kutu açma" kulağa oldukça genel geliyor, bu özel özelliğe başvurduğunu fark etmedim. (Sanırım konuştuğumuzdan beri sahip olmalıydım foreach.)
svick
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.