Tüm tasarım süreçleri, karşılıklı uyumsuz hedefler arasında uzlaşmaya yol açar. Ne yazık ki, &&
C ++ ' da aşırı yüklenmiş operatörün tasarım süreci kafa karıştırıcı bir sonuç verdi: İstediğiniz özellik &&
- kısa devre davranışı - atlandı.
Tasarım sürecinin bu talihsiz yerde, bilmediğim yerde nasıl sonuçlandığına dair detaylar. Bununla birlikte, daha sonraki bir tasarım sürecinin bu hoş olmayan sonucu nasıl dikkate aldığını görmek önemlidir. C # aşırı &&
operatör olan kısa devre. C # tasarımcıları bunu nasıl başardılar?
Diğer cevaplardan biri "lambda kaldırma" yı gösteriyor. Yani:
A && B
ahlaken eşdeğer bir şey olarak gerçekleştirilebilir:
operator_&& ( A, ()=> B )
burada ikinci argüman tembel değerlendirme için bir mekanizma kullanır, böylece değerlendirildiğinde ifadenin yan etkileri ve değeri üretilir. Aşırı yüklenmiş operatörün uygulanması, tembel değerlendirmeyi yalnızca gerektiğinde yapacaktır.
C # tasarım ekibinin yaptığı bu değil. (Kenara: lambda kaldırma olsa olduğunu bunu yapmak için zamanı geldiğinde ne yaptığını ifade ağacı temsil ait ??
.. Belirli dönüşüm işlemlerini gerektirir operatörü, tembel yapılacak ayrıntılı olarak ancak büyük bir Arasöz olacağını anlatan yeterli demek: lambda kaldırma çalışıyor ancak bundan kaçınmak istediğimiz kadar ağır.)
Aksine, C # çözümü sorunu iki ayrı soruna ayırır:
- sağ taraftaki işleneni değerlendirmeli miyiz?
- yukarıdakilerin cevabı "evet" ise, iki işleneni nasıl birleştirebiliriz?
Bu nedenle, &&
doğrudan aşırı yüklenmeyi yasa dışı hale getirerek sorun çözülür . Aksine, C # 'da , her biri bu iki sorudan birini yanıtlayan iki işleç aşırı yüklenmelidir .
class C
{
// Is this thing "false-ish"? If yes, we can skip computing the right
// hand size of an &&
public static bool operator false (C c) { whatever }
// If we didn't skip the RHS, how do we combine them?
public static C operator & (C left, C right) { whatever }
...
(Bir kenara: aslında, üç. C #, operatörün false
sağlanması durumunda, operatörün de sağlanması true
gerektiğini gerektirir , bu da soruyu cevaplar: bu şey "true-ish?" Dir.Genellikle böyle bir operatörü sağlamak için hiçbir neden olmaz. her ikisini de gerektirir.)
Formun bir ifadesini düşünün:
C cresult = cleft && cright;
Derleyici, bu sözde-C # yazdığınızı düşündüğü gibi bunun için kod üretir:
C cresult;
C tempLeft = cleft;
cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);
Gördüğünüz gibi, sol taraf daima değerlendirilir. Eğer "false-ish" olduğu belirlenirse, sonuç budur. Aksi takdirde, sağ taraf değerlendirilir ve istekli kullanıcı tanımlı operatör &
çağrılır.
||
Operatör bir operatörün çağırma doğru ve istekli olarak, benzer bir şekilde tanımlanır |
operatör:
cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright);
Dört operatörleri tanımlayarak - true
, false
, &
ve |
- C # söylemek sadece verir cleft && cright
olmayan kısa devre değil, aynı zamanda cleft & cright
ve aynı zamanda if (cleft) if (cright) ...
ve c ? consequence : alternative
ve while(c)
ve böyle devam eder.
Şimdi, tüm tasarım süreçlerinin uzlaşmanın sonucu olduğunu söyledim. Burada C # dil tasarımcıları kısa devre &&
ve ||
doğru olmayı başardı , ancak bunu yapmak için iki yerine dört operatörün aşırı yüklenmesi gerekiyor , bu da bazı insanların kafa karıştırıcı buluyor. Operatör true / false özelliği, C # 'da en az anlaşılan özelliklerden biridir. C ++ kullanıcılarına aşina olan mantıklı ve anlaşılır bir dile sahip olma amacına kısa devre yapma arzusu ve lambda kaldırma veya diğer tembel değerlendirme biçimlerini uygulama isteği karşı çıkmıştır. Bunun makul bir uzlaşmaya pozisyon olduğunu düşünüyorum, ama buna fark etmek önemlidir olduğu bir uzlaşma pozisyonu. Sadece farklı C ++ tasarımcılarına göre daha uzlaşma.
Bu tür operatörler için dil tasarımı konusu sizi ilgilendiriyorsa, C # 'ın nulllable Booleans üzerinde bu operatörleri neden tanımlamadığına dair dizimi okumayı düşünün:
http://ericlippert.com/2012/03/26/null-is-not-false-part-one/
operator&&(const Foo& lhs, const Foo& rhs) : (lhs.bars == 0)