C# 返回有意义的返回值的方法

C# 返回有意义的返回值的方法,c#,C#,我在C#工作,所以我在C#下发布了这个问题,尽管这可能是一个可以用任何编程语言回答的问题 有时,我会创建一个方法来做一些事情,例如将用户登录到网站。我经常从方法返回布尔值,但这通常会导致问题,因为布尔值返回值不传递任何上下文。如果用户登录时发生错误,我无法知道是什么原因导致了错误 下面是我当前使用的一个方法的示例,但我希望对其进行更改,使其返回的不仅仅是0或1 public bool LoginToTwitter(String username, String password) { /

我在C#工作,所以我在C#下发布了这个问题,尽管这可能是一个可以用任何编程语言回答的问题

有时,我会创建一个方法来做一些事情,例如将用户登录到网站。我经常从方法返回布尔值,但这通常会导致问题,因为布尔值返回值不传递任何上下文。如果用户登录时发生错误,我无法知道是什么原因导致了错误

下面是我当前使用的一个方法的示例,但我希望对其进行更改,使其返回的不仅仅是0或1

public bool LoginToTwitter(String username, String password)
{
    // Some code to log the user in
}
上述方法只能返回True或False。这很有效,因为我可以调用以下命令:

if(http.LoginToTwitter(username, password))
{
    // Logged in
} else {
    // Not Logged in
}
但问题是我无法知道用户为什么没有登录。可能存在许多原因,例如:用户名/密码组合错误、帐户挂起、帐户需要用户注意等。但是使用以下方法和逻辑,不可能知道这一点


我有哪些替代方法?

您可以创建并返回带有预期登录结果的
enum

public enum LoginResult
{
   Success,
   AccountSuspended,
   WrongUsername,
   WrongPassword,
}
然后使用方法中的枚举类型返回:

public LoginResult LoginToTwitter(String username, String password)
{
    // Some code to log the user in
}

您可以选择抛出附加了相关消息的异常(并让调用方法处理该异常),或者让函数返回具有不同状态的
enum
(例如
LoginState.Success
LoginState.IncorrectPassword
等)


如果您使用的是异常,最好让函数不返回任何内容(
public void LoginToTwitter
),但是如果您使用的是
enum
,请确保将返回类型设置为
enum
public LoginState LoginToTwitter
)的名称。如果您只关心结果,而不关心任何元数据,请返回一些枚举。将可用值设置为
Success
Suspended
等(所有可能的结果)


如果您需要更多详细信息,您可以始终使用异常。基本上遵循“告诉,不要问”的思想,编写函数时只在成功时返回所需的值(例如,用户id?或者如果您有一些全局登录状态,则可能什么都没有),否则会抛出异常并详细描述失败。关于层次结构本身,您很可能应该使用一些更具体的子类实现一个
LoginException
,并且只捕获那些子类。(这样可以很容易地验证是否处理了所有相关的异常,以及是否将所有未知的异常传递到更高的级别)

根据干净的代码趋势,您应该为您的方法提供一个有意义的全名,以显示其意图

要了解日志记录操作无法完成时会发生什么情况,您可以在流中引入异常,并在调用方上下文中处理它


请参见

如其他答案所示,返回枚举或引发异常都是合理的。但我倾向于返回一个异常。听起来很疯狂,但它让您的调用者决定是使用错误检查还是异常处理。而且,与枚举不同,异常是分层的,因此它更容易处理所有类别的故障,并且可以携带任意的额外数据


我想Sayse也有类似的想法,但他删除了他的答案,也从未真正解释过。

你可以使用c语言中常用的习惯用法。赋值表达式的结果是表达式本身-这意味着您可以在计算结果代码是否为特定值的同时捕获结果代码:

if ((status = DoSomething()) == AnErrorEnum.NotAnError)
{//success handler
}
else
{//failure handler
}
我被要求提供一个指向MSDN文章的链接-以下是该规范的旧版本:


“简单赋值表达式的结果是分配给左操作数的值。结果的类型与左操作数相同,并且始终被分类为值。”

@jvra如果有任何意外的异常,我认为应该像其他一些答案所示,重新抛出它们。但是,您的代码应该能够处理所有预期情况:错误的用户名、错误的密码、帐户挂起等。。。并在枚举中返回应用程序要处理的预期案例。但事实是,当您要处理其他错误枚举时。您的代码可以随着常量枚举的增长而增长。但是,如果您知道将来不能有更多的常量enum,这是可以接受的。@jvra在这种情况下,我仍然希望返回一个enum。它将以强类型的方式处理所有当前预期的结果。如果将来需要添加任何代码,并且代码是您自己的,则可以添加到枚举中。如果您不拥有代码,并且它需要保留,那么您最终将处理异常,而不会使用强类型(我相信这是另一种选择)。枚举在哪里定义?我已经在包含LoginToTwitter方法的HTTP类中定义了它,并将该方法的返回类型设置为LoginResult。但是,在Form类(调用http.LoginToTwitter方法的地方)中,LoginResult枚举是未定义的。如果我尝试执行LoginResult result=http.LoginToTwitter(…),则枚举未定义。那么定义枚举的最佳位置在哪里呢?@JamesJeffery枚举是否设置为public?因此基本上,
null
意味着成功——这似乎有点违反直觉。当然,如果你真的需要一个返回值,比如说用户信息。。。我可以在Smalltalk这样的语言中找到一个很好的例子,它是动态类型的,但是像C#这样的静态类型语言使这个过程变得很麻烦。@cHao:如果进一步的处理需要返回一些其他信息,那么抛出异常就更有意义了。但如果登录失败是预期的结果。。。我不会在非特殊情况下使用
throw
。我很惊讶没有人认为
LoginResult
类型不是