मैं C ++ के दृष्टिकोण से उत्तर दूंगा। मुझे पूरा यकीन है कि सभी मुख्य अवधारणा C # के लिए हस्तांतरणीय हैं।
ऐसा लगता है कि आपकी पसंदीदा शैली "हमेशा अपवाद फेंकें":
int CalculateArea(int x, int y) {
if (x < 0 || y < 0) {
throw Exception("negative side lengths");
}
return x * y;
}
यह C ++ कोड के लिए एक समस्या हो सकती है क्योंकि अपवाद-हैंडलिंग भारी है - यह विफलता के मामले को धीरे-धीरे चलाता है, और विफलता के मामले को मेमोरी आवंटित करता है (जो कभी-कभी उपलब्ध भी नहीं होता है), और आम तौर पर चीजों को कम अनुमानित करता है। ईएच का भारीपन एक कारण है जो आप लोगों को यह कहते हुए सुनते हैं कि "नियंत्रण प्रवाह के लिए अपवादों का उपयोग न करें।"
तो है (जैसे कि कुछ पुस्तकालयों <filesystem>
) का उपयोग क्या सी ++ एक "दोहरी एपीआई," कहते हैं या क्या सी # कॉल Try-Parse
पैटर्न (धन्यवाद पीटर टिप के लिए!)
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
}
आप "दोहरी APIs" के साथ समस्या को तुरंत देख सकते हैं: बहुत सारे कोड दोहराव, उपयोगकर्ताओं के लिए कोई मार्गदर्शन नहीं, जिसके लिए API का उपयोग करने के लिए "सही" है, और उपयोगकर्ता को उपयोगी त्रुटि संदेशों ( CalculateArea
) के बीच एक कठिन विकल्प बनाना चाहिए गति ( TryCalculateArea
) क्योंकि तेज संस्करण हमारे उपयोगी "negative side lengths"
अपवाद को लेता है और इसे एक बेकार में समतल कर देता है false
- "कुछ गलत हो गया, मुझसे मत पूछो कि क्या या कहाँ।" (कुछ दोहरी API, के रूप में एक अधिक अर्थपूर्ण त्रुटि प्रकार का उपयोग int errno
सी ++ के या std::error_code
है, लेकिन है कि अभी भी आपको बता नहीं है जहां त्रुटि हुई - सिर्फ इतना है कि यह किया था कहीं होते हैं।)
यदि आप यह तय नहीं कर सकते हैं कि आपके कोड को कैसे व्यवहार करना चाहिए, तो आप हमेशा कॉल करने वाले के ऊपर निर्णय को किक कर सकते हैं!
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; });
यह अनिवार्य रूप से आपके सहकर्मी क्या कर रहा है; सिवाय इसके कि वह "त्रुटि हैंडलर" को एक वैश्विक चर में विभाजित कर रहा है:
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);
वैश्विक राज्य में स्पष्ट फ़ंक्शन मापदंडों से महत्वपूर्ण मापदंडों को स्थानांतरित करना लगभग हमेशा एक बुरा विचार है। मैं इसकी अनुशंसा नहीं करता हूं। (तथ्य यह है कि यह आपके मामले में वैश्विक स्थिति नहीं है, लेकिन उदाहरण के लिए व्यापक सदस्य राज्य बदनामी को थोड़ा कम करता है, लेकिन बहुत कुछ।)
इसके अलावा, आपका सहकर्मी अनावश्यक रूप से संभावित त्रुटि हैंडलिंग व्यवहारों की संख्या को सीमित कर रहा है। किसी भी त्रुटि से निपटने वाले लंबोदर को अनुमति देने के बजाय , उसने सिर्फ दो पर फैसला किया है:
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);
यह संभवतया इनमें से किसी भी संभावित रणनीति से बाहर "खट्टा स्थान" है। आपने सभी लचीलेपन को अंत-उपयोगकर्ता से दूर ले जाकर उन्हें अपने दो त्रुटि-हैंडलिंग कॉलबैक में से एक का उपयोग करने के लिए मजबूर किया है ; और आपको साझा वैश्विक स्थिति की सभी समस्याएं मिल गई हैं; और आप अभी भी हर जगह उस सशर्त शाखा के लिए भुगतान कर रहे हैं।
अंत में, C ++ में एक सामान्य समाधान (या सशर्त संकलन के साथ कोई भी भाषा) उपयोगकर्ता को अपने संपूर्ण कार्यक्रम के लिए निर्णय लेने के लिए बाध्य करेगा, विश्व स्तर पर, संकलन समय पर, ताकि अन-ली गई कोडपथ को पूरी तरह से अनुकूलित किया जा सके:
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);
कुछ इस तरह से काम करता है का एक उदाहरण सी और सी ++ में assert
मैक्रो है, जो प्रीप्रोसेसर मैक्रो पर उसके व्यवहार को स्थिति देता है NDEBUG
।