Câu trả lời đơn giản là, bất cứ khi nào một hoạt động là không thể (vì một trong hai ứng dụng HOẶC vì nó sẽ vi phạm logic kinh doanh). Nếu một phương thức được gọi và không thể thực hiện những gì phương thức được viết để làm, hãy ném Ngoại lệ. Một ví dụ điển hình là các hàm tạo luôn ném ArgumentExceptions nếu một thể hiện có thể được tạo bằng các tham số được cung cấp. Một ví dụ khác là UnlimitedOperationException, được ném khi một hoạt động không thể được thực hiện do trạng thái của một thành viên khác hoặc các thành viên của lớp.
Trong trường hợp của bạn, nếu một phương thức như Đăng nhập (tên người dùng, mật khẩu) được gọi, nếu tên người dùng không hợp lệ, thì thực sự đúng khi ném UserNameNotValidException hoặc PasswordNotC CorrException nếu mật khẩu không chính xác. Người dùng không thể đăng nhập bằng (các) tham số được cung cấp (nghĩa là không thể vì nó sẽ vi phạm xác thực), vì vậy hãy ném Ngoại lệ. Mặc dù tôi có thể thừa hưởng hai Ngoại lệ của bạn từ ArgumentException.
Như đã nói, nếu bạn muốn KHÔNG ném Ngoại lệ vì lỗi đăng nhập có thể rất phổ biến, một chiến lược là thay vào đó tạo ra một phương thức trả về các loại đại diện cho các lỗi khác nhau. Đây là một ví dụ:
{ // class
...
public LoginResult Login(string user, string password)
{
if (IsInvalidUser(user))
{
return new UserInvalidLoginResult(user);
}
else if (IsInvalidPassword(user, password))
{
return new PasswordInvalidLoginResult(user, password);
}
else
{
return new SuccessfulLoginResult();
}
}
...
}
public abstract class LoginResult
{
public readonly string Message;
protected LoginResult(string message)
{
this.Message = message;
}
}
public class SuccessfulLoginResult : LoginResult
{
public SucccessfulLogin(string user)
: base(string.Format("Login for user '{0}' was successful.", user))
{ }
}
public class UserInvalidLoginResult : LoginResult
{
public UserInvalidLoginResult(string user)
: base(string.Format("The username '{0}' is invalid.", user))
{ }
}
public class PasswordInvalidLoginResult : LoginResult
{
public PasswordInvalidLoginResult(string password, string user)
: base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
{ }
}
Hầu hết các nhà phát triển được dạy để tránh Ngoại lệ vì chi phí gây ra bằng cách ném chúng. Thật tuyệt khi có ý thức về tài nguyên, nhưng thường không phải trả giá cho thiết kế ứng dụng của bạn. Đó có lẽ là lý do bạn được khuyên không nên ném hai Ngoại lệ của mình. Có nên sử dụng Ngoại lệ hay không thường làm giảm mức độ thường xuyên của Ngoại lệ. Nếu đó là một kết quả khá phổ biến hoặc khá đáng mong đợi, thì đó là khi hầu hết các nhà phát triển sẽ tránh Ngoại lệ và thay vào đó tạo ra một phương pháp khác để biểu thị sự thất bại, vì tiêu thụ tài nguyên được cho là.
Đây là một ví dụ về việc tránh sử dụng Ngoại lệ trong một kịch bản như vừa mô tả, sử dụng mẫu Thử ():
public class ValidatedLogin
{
public readonly string User;
public readonly string Password;
public ValidatedLogin(string user, string password)
{
if (IsInvalidUser(user))
{
throw new UserInvalidException(user);
}
else if (IsInvalidPassword(user, password))
{
throw new PasswordInvalidException(password);
}
this.User = user;
this.Password = password;
}
public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
{
if (IsInvalidUser(user) ||
IsInvalidPassword(user, password))
{
return false;
}
validatedLogin = new ValidatedLogin(user, password);
return true;
}
}