2014-04-02 6 views
12

मैं एकाधिक परिणाम मानों के साथ एक विधि के लिए फायदे और नुकसान खोजने की कोशिश कर रहा हूं।बेस्ट प्रैक्टिस रिटर्न वैल्यू बनाम अपवाद बनाम एनम

उदाहरण के लिए मैं लॉगिन-विधि का उपयोग कर रहा हूं। अगर लॉगिन सफल हुआ, तो यह गुजर जाएगा, अन्यथा मुझे यह जानना होगा कि यह क्यों विफल हुआ।

1. वापसी सही या गलत (नहीं पर्याप्त जानकारी)

bool Login(string user, string password); 

2. वापसी सच है, अगर यह सफल रहा था, अन्यथा एक अपवाद

public class UnknownUserException : Exception { } 
public class WrongPasswordException : Exception { } 
bool Login(string user, string password); 

3 फेंक देते हैं। कुछ भी वापस नहीं। , एक अपवाद फेंक अगर यह सफल

public class UnknownUserException : Exception { } 
public class WrongPasswordException : Exception { } 
void Login(string user, string password); 

4. नहीं था वापसी एक enum मूल्य

enum LoginResult 
{ 
    Successful 
    UnknownUser, 
    WrongPassword 
} 
LoginResult Login(string user, string password); 

"लॉगिन" सिर्फ एक उदाहरण मामला है। मैं जानना चाहता हूं कि विभिन्न कार्यान्वयन के फायदे और नुकसान क्या हैं, और किस मामले के लिए वे कम या ज्यादा उपयुक्त हैं।

+0

1 और 2 स्पष्ट रूप से विचार के लायक नहीं हैं। # 3 इस बात की नस में है कि चीजें आम तौर पर कैसे की जाती हैं, लेकिन यह पहचानने के लिए सुसज्जित एकमात्र व्यक्ति शायद आपके मामले में # 4 अधिक उपयुक्त है। – Jon

+0

एपीआई तुल्यकालिक या async है? –

+0

तुल्यकालिक, क्षमा करें :) – Jan

उत्तर

3

आपको अधिक राय वाले उत्तर मिलेगा, अगर मैं कर रहा था तो मैं 3 & गठबंधन करूंगा 4. एक enum के साथ LoginFailedException फेंक दो। अपवाद विकल्प चुनने के लिए

void Login(string user, string password);//Or return a bool(redundant though) 

class LoginFailedException : ApplicationException 
{ 
    public LoginFailReason Reason {get; private set;} 
    public LoginFailedException(LoginFailReason reason) 
    { 
     this.Reason = reason; 
    } 
} 

enum LoginFailReason 
{ 
    UnknownUser, 
    WrongPassword 
} 

कारण: आप वापसी मान चुनें केवल दृष्टिकोण, अपने एपीआई के उपयोगकर्ताओं (ग्राहक, या अन्य डेवलपर्स हो सकता है) एपीआई को नजरअंदाज करने का मौका मिल सकता है मान लें।

instance.Login(user, password); 
var accountInfo = instance.GetAccountInfo();//Assuming logged in; going to explode 

कौन जानता है कि वे इस

if(instance.Login(user, password) == LoginResult.Successful)) 
{ 
    var accountInfo = instance.GetAccountInfo(); 
} 

की तरह करने के लिए तो, चेहरे में IMO फेंक अपवाद कह मैं इतना और इतनी कारण की वजह से आपके प्रवेश अनुरोध संसाधित नहीं कर सकता है। इसे सरल बनाओ।

+4

मुझे यह दृष्टिकोण पसंद है, हालांकि इसमें एक अपवाद फेंकना गलत लगता है, इमो, एक आम की तरह लगता है परिदृश्य। मुझे लगता है कि अपवादों को 'असाधारण' परिदृश्यों में इस्तेमाल किया जाना चाहिए जहां गहरे स्तर पर कुछ गलत है। – Moeri

+2

@Moeri मुझे विश्वास है कि यह सही तरीका है, लॉगिन विफलता सामान्य स्थिति नहीं है यह ** असाधारण ** शर्त है, मान लीजिए कि आप केवल एक एनम स्वीकृति चुन रहे हैं, और आप एक सार्वजनिक एपीआई विकसित करते हैं, तो क्या होगा यदि उपयोगकर्ता ' वापसी मूल्य की जांच न करें और केवल 'लॉगिन();' पर कॉल करें और लॉग इन करें। यह कहने के लिए फेंक दो कि कुछ गलत हो गया है (जैसा कि एसक्लसेवर एसक्लएक्सप्शन के माध्यम से करता है) –

+0

@ मोरी अपवाद 'सी-स्टाइल' स्टेटस कोड और 'GetLastError() 's को बदलने के लिए हैं। आप उस दृष्टिकोण के साथ 'आंतरिक अपवाद' के विचार को कैसे कार्यान्वित करेंगे? * मामला जब त्रुटि दो या अधिक परतों दूर होती है * – tchelidze

1

निश्चित रूप से अपवाद नहीं। एक असफल लॉगिन शायद ही कभी "असाधारण" मामला है और यह एप्लिकेशन के लिए तर्क का सामान्य पाठ्यक्रम है। यदि आप अपवाद का उपयोग करते हैं तो असफल लॉगिन के मामले को संभालने के अलावा आपको किसी भी अन्य कारण के लिए अपवाद हैंडलर के साथ लॉग इन करना होगा। ऐसा लगता है कि तर्क प्रवाह के लिए अपवादों का उपयोग करने की बहुत परिभाषा है, जो सही नहीं है।

यदि आपको लॉगिन जानकारी से आवश्यक हमेशा नहीं है, लेकिन आपके मामले में हो सकता है), # 4 उचित लगता है। आप इसे एक कदम आगे ले सकता है और यह एक वस्तु बनाने:

public class LoginResult 
{ 
    // an enum for the status 
    // a string for a more specific message 
    // a valid user object on successful login 
    // etc. 
} 

या, इसके लिए तर्क, एक वर्ग के बजाय एक अपरिवर्तनीय struct पर निर्भर करता है। (सुनिश्चित करें कि संरचना अपरिवर्तनीय है, म्यूटेबल structs सिर्फ परेशानी के लिए पूछ रहे हैं।) बिंदु यह है कि आप परिणाम ऑब्जेक्ट पर तर्क और कार्यक्षमता के सभी प्रकार लागू कर सकते हैं, जो कि आप जिस दिशा में जा रहे हैं वह प्रतीत होता है।

1

बेशक यह निश्चित स्थिति पर निर्भर करता है, लेकिन मुझे यहाँ मेरी व्यक्तिपरक टिप्पणियों के एक जोड़े प्रदान करते हैं:

  1. मुझे यकीन है कि इस तरह के मामलों से बचा जाना चाहिए हूँ। विधि का नाम बताता है कि यह "लॉगिन" जैसे किसी भी ऑपरेशन को निष्पादित करता है। विधि के नाम के अनुसार हम यहां किसी भी परिणाम की उम्मीद नहीं कर सकते हैं। क्या आप bool मान वापस करने की विधि चाहते हैं, यह IsLoggedIn(userName) जैसे नाम देने के लिए बेहतर है। इसके अलावा आपको कभी पता नहीं चलेगा कि आपको वापस आने वाले मूल्यों का सेट बढ़ाने की आवश्यकता है या नहीं। तो enum यह भी ध्यान में रखते हुए बहुत बेहतर है कि मूल्य का उद्देश्य नाम में सरल bool के बजाय प्रतिबिंबित होता है।

  2. ऊपर जैसा ही है। यहां निष्कर्ष पूरे निष्पादन पदानुक्रम को रोकने में मदद करते हैं (जो निश्चित रूप से परिणाम लौटने के बजाय कॉल कॉलर में 1 से अधिक विधि शामिल कर सकते हैं) और कॉलर को उचित निर्णय लेने दें। मेरे लिए अधिक लचीला समाधान। वर्तमान स्थिति में मैं केवल पैरामीटर सत्यापन के लिए अपवादों का उपयोग करता हूं। "गलत उपयोगकर्ता नाम/पासवर्ड" जैसी स्थितियां असाधारण नहीं हैं। वे उपयोग के मामलों के दृष्टिकोण से सामान्य हैं। null पैरामीटर या गलत पैरामीटर प्रारूप असाधारण मामले हैं।

  3. यदि आपको मूल्य वापस करने की विधि की आवश्यकता नहीं है, तो वह तरीका है। भूलें कि आपको नेविगेशन के रूप में अपवादों का उपयोग नहीं करना चाहिए। मेरा मतलब है UserSuccessfullyCreatedException या तो।

  4. जैसा कि मैंने ऊपर बताया है, यह मेरे लिए सबसे अच्छा तरीका है। एकल बिंदु enum मानों के रूप में सत्यापन अपवादों को नहीं रखना है। इसके लिए आपके पास अपवाद हैं।

तो enum परिणाम सत्यापन के लिए अपवाद भी एक तरीका है।

आप विधि निष्पादन के दौरान सभी त्रुटियों को इकट्ठा करने के लिए चाहते हैं, तो आप शायद सत्यापन errors` विधि निष्पादन के दौरान हुई सहित सभी जानकारी (रैप करने के लिए विशेष LoginOperationResult वर्ग बनाने के लिए पसंद करेंगे।

class OperationResult 
{ 
    public OperationStatus Status { get; set; } 

    public IEnumerable<ValidationError> Errors { get; set; } 
    // or list of exceptions 
} 

class LoginOperationResult : OperationResult 
{ 
    // Login result specific data. 
} 

enum OperationStatus 
{ 
    Success, 
    Denied, 
    ValidationFailed, 
    // etc. 
} 
0

मैं आमतौर पर अपनी परियोजनाओं में इस दृष्टिकोण का उपयोग:

हस्ताक्षर:

bool TryLogin(string username, string password, out User user); 

उपयोग:

User user; 
if(userService.TryLogin(username, password, out user))) 
{ 
    // do stuff with user 
} 
else 
{ 
    // show "login failed" 
} 

आप इस विस्तार कर सकता है आपके Enum वापस जाने के लिए:

हस्ताक्षर:

enum LoginResult 
{ 
    Successful 
    UnknownUser, 
    WrongPassword 
} 

LoginResult TryLogin(string username, string password, out User user); 

उपयोग:

User user; 
LoginResult loginResult; 
if((loginResult = userService.TryLogin(username, password, out user)) == LoginResult.Successful) 
{ 
    // do stuff with user 
} 
else 
{ 
    // do stuff with loginResult 
} 
संबंधित मुद्दे