Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 流量控制模式和最佳实践_C# - Fatal编程技术网

C# 流量控制模式和最佳实践

C# 流量控制模式和最佳实践,c#,C#,我们和同事就流控制模式和通用代码设计进行了争论。需要您的意见-编写代码的更好/更干净/首选方法是什么 这是针对MVC 3的,但这并不重要。 第1版: public ActionResult Login(LoginData loginData) { if (!ModelState.IsValid) { ShowGlobalError("Invalid credentials."); return View(loginData); }

我们和同事就流控制模式和通用代码设计进行了争论。需要您的意见-编写代码的更好/更干净/首选方法是什么

这是针对MVC 3的,但这并不重要。
第1版:

public ActionResult Login(LoginData loginData)
{
    if (!ModelState.IsValid)
    {
        ShowGlobalError("Invalid credentials.");
        return View(loginData);
    }

    UserProfile profile = null;
    try
    {
        // see if we have profile with those credentials
        profile = this.RetrieveUserProfile(loginData.Email.Trim(), loginData.Password.Trim());  // this just goes to db and tries to get user profile. Returns null if profile isn't found
    }
    catch (Exception ex)
    {
        ShowGlobalError("DB is down");
        LogError(...);
        return View(loginData);
    }


    if (profile == null)
    {
        // nope, we don't.. ask again
        ShowGlobalError("Invalid credentials.");
        return View(loginData);
    }

    // ok, we're good
    Session["Profile"] = profile;
    FormsAuthentication.SetAuthCookie(profile.Email, false);
    FormsAuthentication.RedirectFromLoginPage(profile.Email, loginData.EnablePermanentCookie);

    return View(loginData);
}
第2版:

public ActionResult Login(Credentials credentials){
    try{
        PersonalProfile profile = AuthenticateUser(credentials);
        SetProfileSessionstate(profile);    // this does 'Session["Profile"] = profile;'
        SetFormsAuthenticationAndRedirect(profile); 
    }
    catch(Exception ex){
            ShowGlobalError("invalid login, please try again.");
    }
    return View(credentials);
}

public void SetFormsAuthenticationAndRedirect(PersonalProfile profile){
     FormsAuthentication.SetAuthCookie(profile.Email, loginData.EnablePermanentCookie);
     FormsAuthentication.RedirectFromLoginPage(profile.Email, loginData.EnablePermanentCookie);
}
版本1充斥着返回语句,版本2使用try/catch进行流控制。 那么,哪种方式更好,或者我们都做错了,有更好的方式可以分享吗


谢谢

我认为版本2没有使用try/catch进行流控制。使用try/catch进行流控制看起来像

我认为这两种方法都是有效的,尽管第二种方法对我来说更容易遵循

编辑:

异常的存在是为了停止执行并通知调用方法“我无法完成执行,原因如下”。在某种程度上,这就是流量控制

考虑以下代码

try
{
    foo = doSomething1();  // Could throw an Exception here
    doSomething2(foo);
}
catch (Exception ex)
{
    // Show error message
}
这在技术上可能是“流控制”,但这种流控制说“嘿,这个过程无法完成,原因就在这里。”这正是例外的原因

考虑以下代码:

try
{
    foo = doSomething1();  // Could throw an Exception here
}
catch (Exception ex)
{
    // Show error message and return
}

if (foo != null)
{
    doSomething2(foo);
}
else
{
    // Show an error message and return
}
这段代码与前一段代码做的事情完全相同,但是更长,具有相同的异常处理开销,并且更复杂。在这两种情况下,除非doSomething1成功完成,否则不会执行doSomething2。那么为什么不使用更简单的代码呢

编辑:

至少,您可以这样做,它将围绕您的流量控制规则工作:

public ActionResult Login(Credentials credentials)
{
    try
    {
        innerLogin(credentials);
    }
    catch(Exception ex)
    {
        ShowGlobalError("invalid login, please try again.");
    }
    return View(credentials);
}

private void innerLogin(Credentials credentials)
{
    PersonalProfile profile = AuthenticateUser(credentials);
    SetProfileSessionstate(profile);
    SetFormsAuthenticationAndRedirect(profile); 
}

我想说,在这个场景中,流控制的最佳方法是tester-doer模式。就我个人而言,我从不使用异常来控制我的应用程序流

if (this.CanAuthenticateUser(credentials))
{
    PersonalProfile profile = AuthenticateUser(credentials);
    SetProfileSessionstate(profile);    // this does 'Session["Profile"] = profile;'
    SetFormsAuthenticationAndRedirect(profile);
}
else
{
    ShowGlobalError("invalid login, please try again.");
}

return View(credentials);
我喜欢1比2好得多

第二是惰性编码

no.1显式捕获错误

依靠异常捕捉逻辑错误或错误不是一个好主意 在#2中,如果profile为null,则通常不检查它,而依靠抛出异常来捕获异常是代价高昂的操作
并且应该只依赖于不可预见的逻辑结果(例外!)

那么版本1应该等同于版本2吗?因为看起来它们做的事情不一样。是的,它们基本上做的是相同的事情-用户登录转换1正在测试配置文件是否实际被检索,版本2尝试访问配置文件属性,如果配置文件不存在,则访问将失败-然后转到catch语句。如果配置文件不是从AuthenticateUser()接收的,将引发异常,对吗?您正在catch块中捕获该异常,这意味着您不需要测试它是否实际收到。如果AuthenticateUser()未引发异常,或者存在名为CanAuthenticate()的方法,则情况会有所不同。如果您可以使用像CanAuthenticate(凭据)这样的东西来避免异常,那么就这样做。然后CanAuthenticate将必须返回一个三态结构(true、false、DatabaseExceptionTown),并且在这一点上会变得混乱,依我看。如果是这样的话,那么请继续使用现有的结构。关键是,如果发生异常,您需要停止登录过程并显示错误消息。版本1和版本2都可以这样做。坦白地说,我认为您甚至不应该在Login()方法中捕获任何异常。让异常冒泡到调用Login的方法,并让该方法处理错误。AuthenticateUser转到数据库并尝试获取用户配置文件。因此,对于这个方法,您仍然需要一个try/catch,并且您仍然需要检查配置文件是否被实际检索,或者对SetProfileSessionstate进行一个try/catch,因为它将访问配置文件的属性。我想您没有领会我文章的要点。这里有一对方法,CanAuthenticateUser和AuthenticateUser。CanAuthenticateUser(测试仪)返回一个布尔值,指示AuthenticateUser(doer)是否成功。提供这样的代码路径总是一个好主意,这样可以避免抛出异常。因此,为什么不使用#2,只需添加“if(profile==null){batherror();return;}”?作为旁注,我完全同意捕获一般异常而不是更具体的异常是一个坏主意。但我不认为这就是问题所在。我捕获异常的原因是这个try/catch块只包装数据库操作。所以,如果在那个时候抛出异常,它很可能是数据库相关的,除非我幸运地从MemoryException或类似的东西中得到了帮助。是的,我有点懒散,但我不认为在这段特定的代码中有特定捕获的价值。当您添加if(profile==null)时,它几乎会变成#1:)