Prosta odpowiedź brzmi: ilekroć operacja jest niemożliwa (z powodu dowolnej aplikacji LUB z powodu naruszenia logiki biznesowej). Jeśli metoda jest wywoływana i nie można zrobić tego, co metoda została napisana, wykonaj wyjątek. Dobrym przykładem jest to, że konstruktory zawsze zgłaszają wyjątki ArgumentException, jeśli instancji nie można utworzyć przy użyciu podanych parametrów. Innym przykładem jest InvalidOperationException, który jest zgłaszany, gdy operacja nie może zostać wykonana z powodu stanu innego członka lub członków klasy.
W twoim przypadku, jeśli wywoływana jest metoda taka jak Login (nazwa użytkownika, hasło), jeśli nazwa użytkownika jest niepoprawna, to rzeczywiście poprawne jest wygenerowanie UserNameNotValidException lub PasswordNotCorrectException, jeśli hasło jest niepoprawne. Nie można się zalogować przy użyciu dostarczonych parametrów (tj. Jest to niemożliwe, ponieważ naruszyłoby to uwierzytelnianie), więc zgłoś wyjątek. Chociaż mogę mieć dwa wyjątki dziedziczone z ArgumentException.
Powiedziawszy to, jeśli nie chcesz zgłaszać wyjątku, ponieważ niepowodzenie logowania może być bardzo częste, jedną ze strategii jest utworzenie metody zwracającej typy reprezentujące różne niepowodzenia. Oto przykład:
{ // 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))
{ }
}
Większość programistów uczy się unikać wyjątków ze względu na narzut związany z ich rzucaniem. Wspaniale jest być świadomym zasobów, ale zwykle nie kosztem projektowania aplikacji. To prawdopodobnie powód, dla którego kazano ci nie rzucać dwoma wyjątkami. To, czy użyć wyjątków, czy nie, zwykle sprowadza się do częstotliwości występowania wyjątku. Jeśli jest to dość powszechny lub dość oczekiwany wynik, wtedy większość programistów uniknie wyjątków i zamiast tego stworzy inną metodę sygnalizowania niepowodzenia z powodu domniemanego zużycia zasobów.
Oto przykład unikania używania wyjątków w scenariuszu opisanym właśnie przy użyciu wzorca Try ():
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;
}
}