C ++ açısından cevap vereceğim. Bütün temel kavramların C # 'ya transfer edilebildiğinden eminim.
Tercih ettiğiniz stil "her zaman istisnalar atıyor" gibi geliyor:
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
throw Exception("negative side lengths");
}
return x * y;
}
Bu istisna işleme ağır olduğu için C ++ kodu için bir sorun olabilir - başarısızlık durumunun yavaş çalışmasını sağlar ve başarısızlık durumunun bellek ayırmasını sağlar (bu bazen kullanılabilir bile olmaz) ve genellikle işleri daha az öngörülebilir yapar. EH'nin ağırlığının, insanların “Kontrol akışı için istisnalar kullanma” gibi şeyler söylediğini duymasının bir nedenidir.
Bu yüzden bazı kütüphaneler (örneğin <filesystem>
) C ++ 'ın "çift API" dediği şeyi veya hangi C #' nın Try-Parse
desen dediğini kullanır ( ipucu için teşekkürler Peter !)
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
throw Exception("negative side lengths");
}
return x * y;
}
bool TryCalculateArea(int x, int y, int& result) {
if (x < 0 || y < 0) {
return false;
}
result = x * y;
return true;
}
int a1 = CalculateArea(x, y);
int a2;
if (TryCalculateArea(x, y, a2)) {
// use a2
}
Sorunu hemen "çift API" lerle görebilirsiniz: çok sayıda kod çoğaltması, hangi API'nin "doğru" olduğu konusunda kullanıcılara rehberlik edilmez ve kullanıcı, yararlı hata mesajları ( CalculateArea
) ve speed ( TryCalculateArea
) çünkü daha hızlı sürüm bizim faydalı "negative side lengths"
istisnamızı alır ve onu işe yaramaz hale getirir false
- “bir şeyler ters gitti, bana ne veya nerede olduğunu sorma.” (Bazı ikili API'leri gibi, daha etkileyici hata türünü kullanın int errno
C ++ 'ın ya std::error_code
ama yine de size değil nerede hata oluştu - sadece o did yerde meydana gelir.)
Kodunuzun nasıl davranması gerektiğine karar veremiyorsanız, kararı her zaman arayan kişiye atabilirsiniz!
template<class F>
int CalculateArea(int x, int y, F errorCallback) {
if (x < 0 || y < 0) {
return errorCallback(x, y, "negative side lengths");
}
return x * y;
}
int a1 = CalculateArea(x, y, [](auto...) { return 0; });
int a2 = CalculateArea(x, y, [](int, int, auto msg) { throw Exception(msg); });
int a3 = CalculateArea(x, y, [](int, int, auto) { return x * y; });
Bu aslında iş arkadaşınızın yaptığı şeydir; "hata işleyicisini" global bir değişkene dönüştürmesi dışında:
std::function<int(const char *)> g_errorCallback;
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
return g_errorCallback("negative side lengths");
}
return x * y;
}
g_errorCallback = [](auto) { return 0; };
int a1 = CalculateArea(x, y);
g_errorCallback = [](const char *msg) { throw Exception(msg); };
int a2 = CalculateArea(x, y);
Önemli parametreler Hareketli açık işlev parametreleri içine küresel devlet hemen hemen her zaman kötü bir fikirdir. Tavsiye etmiyorum. ( Sizin durumunuzda küresel bir devlet değil, sadece örnek çapında üye devlet olduğu gerçeği , kötülüğü biraz azaltıyor, ama fazlasıyla azaltıyor.)
Ayrıca, iş arkadaşınız olası hata işleme davranışlarının sayısını gereksiz yere sınırlıyor. Herhangi bir hata işleme lambasına izin vermek yerine , sadece ikisine karar verdi:
bool g_errorViaException;
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
return g_errorViaException ? throw Exception("negative side lengths") : 0;
}
return x * y;
}
g_errorViaException = false;
int a1 = CalculateArea(x, y);
g_errorViaException = true;
int a2 = CalculateArea(x, y);
Bu, muhtemelen bu olası stratejilerden herhangi birinin “ekşi noktası” dır. Tüm esnekliği son kullanıcıdan tam olarak iki hata işleme geri çağrılarınızdan birini kullanmaya zorlayarak aldınız ; ve ortak küresel devletin tüm sorunlarına sahipsiniz; ve hala her yerde bu şartlı şube için para ödüyorsunuz.
Son olarak, C ++ 'da (ya da şartlı derlemeli herhangi bir dilde) ortak bir çözüm, kullanıcının tüm programı için karar vermesi için global olarak, derleme zamanında karar vermesi, böylece alınmamış kod hastalığının tamamen optimize edilmesini sağlamak olacaktır:
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
#ifdef NEXCEPTIONS
return 0;
#else
throw Exception("negative side lengths");
#endif
}
return x * y;
}
// Now these two function calls *must* have the same behavior,
// which is a nice property for a program to have.
// Improves understandability.
//
int a1 = CalculateArea(x, y);
int a2 = CalculateArea(x, y);
Bu şekilde çalışır şeyin bir örnek assert
makro hangi koşullar önişlemci makro üzerindeki davranışını C ve C ++, NDEBUG
.