简体   繁体   English

例外-最佳做法

[英]Exceptions - Best Practices

I have been thinking generally about exception handling. 我一直在思考异常处理。

What would be the best practice for implementing a method that gets a User object based on the supplied username parameter. 实现基于提供的username参数获取User对象的方法的最佳实践是什么。 See below. 见下文。

    /// <summary>
    /// Gets a user.
    /// </summary>
    /// <param name="username">Username</param>
    /// <returns>User instance</returns>
    public Model.User GetUser(string username)
    {
        return Context.Users.SingleOrDefault(u => u.Username.ToLower() == username.ToLower());
    }

if no user exists with that username parameter, would it be better to return a null User object or rather throw a custom exception specifying that the user does not exist. 如果没有使用该username参数的username ,则最好返回一个空的User对象,或者抛出一个自定义异常以指定该用户不存在。

My advice would be if the program cannot continue without a user then throw an exception. 我的建议是,如果没有用户该程序无法继续运行,则抛出异常。 If it is ok that you cannot find a user or that this would be a log-in fail then I would return null. 如果可以找到用户没有问题,或者登录失败,那么我将返回null。 I would only throw an exception if the program could not continue without getting the user and it could not say redirect to log-on again. 如果程序无法在没有获取用户的情况下继续运行并且无法说重定向到再次登录,则只会抛出异常。

Remember throwing an exception is more of an expensive operation that returning null too (I mean nothing noticeable and do think like this (micro-optimization) but exceptions should be used for normal business logic) 请记住,抛出异常更是会返回null的昂贵操作(我的意思是没有什么可察觉的,并且确实像这样(微优化)进行了思考,但异常应用于常规业务逻辑)

Throw an exception. 引发异常。 Otherwise, your caller, and your caller's caller, and everyone else will need to check for null , or will need to handle an empty collection. 否则,您的呼叫者以及您的呼叫者的呼叫者以及其他所有人将需要检查null ,或者需要处理一个空集合。

If this is a general-purpose method, meant to be used in a context where the caller knows he needs to check for null, then I'd do this a bit differently. 如果这是一种通用方法,打算在调用者知道他需要检查null的上下文中使用,那么我会做一些不同的事情。 I would have a private method that returns null if there are no users who match. 我将有一个private方法,如果没有匹配的用户,它将返回null。 I would add a caller which uses the "try" pattern: 我将添加使用“ try”模式的调用方:

public bool TryGetUser(string username, out Model.User user)

and also one that simply returns the user, but throws an exception if not found 还有一个仅返回用户但未找到则抛​​出异常的用户

public Model.User GetUser(string username)

First I just want to suggest an improvement on your method of comparing strings without case sensitivity. 首先,我只想建议您比较不区分大小写的字符串比较方法。

/// <summary>
/// Gets a user.
/// </summary>
/// <param name="username">Username</param>
/// <returns>User instance</returns>
public Model.User GetUser(string username)
{
    return Context.Users.SingleOrDefault(u => 
       string.Compare(u.Username, username, true));
}

String.Compare on MSDN MSDN上的String.Compare

Now my suggestion on this issue 现在我对这个问题的建议

Rather than return null. 而不是返回null。 You may like to return a Null object, using the null object pattern . 您可能想使用null对象模式返回Null对象。

public class User
{

  public static readonly User Null = new Null{Username = "Anonymous"};

  ...

}

Then your method becomes: 然后您的方法变为:

public Model.User GetUser(string username)
{
    return Context.Users.SingleOrDefault(u => 
       string.Compare(u.Username, username, true)) ?? Model.User.Null;
}

This is useful in situations where null is undesirable. 这在不希望使用null情况下很有用。 It removes the need to check for null later. 它消除了以后检查null的需要。 If this user object has rights associated for example, you can just make sure the "null user" has no rights. 例如,如果此用户对象具有关联的权限,则只需确保“空用户”没有权限。

I would say that the calling method can decide whether or not the result of no user being found requires the throwing of an exception. 我要说的是,调用方法可以确定是否找不到用户的结果是否需要引发异常。 If a username is provided, but not found, returning null makes sense to me and letting the calling code decide how it needs to proceed. 如果提供了用户名,但找不到用户名,则返回null对我来说很有意义,然后让调用代码确定如何进行操作。

Given how generic the method is, why would you throw an exception if a supplied username is not found? 考虑到该方法的通用性,如果找不到提供的用户名,为什么还要引发异常? It's one thing if a database error occurs etc, but if the SELECT results in no rows, I think it is not exceptional. 如果发生数据库错误等是一回事,但是如果SELECT结果没有行,我认为这不是例外。

I disagree with the previously posted answers. 我不同意以前发布的答案。

Exceptions should be used only in exceptional circumstances. 例外情况仅应在特殊情况下使用。 Failing to find a matching value is not exceptional. 找不到匹配的值并不罕见。 IMO, returning null is much more elegant- it leaves the decision about whether to throw an exception to the caller, not the callee, and it makes sense; IMO,返回null更为优雅-它决定是否向调用者(而不是被调用者)抛出异常,这是有意义的。 you ask the method for a user and if there is none it returns nothing. 您向用户询问该方法,如果没有该方法,则不返回任何内容。

In addition, your code and the other answers iterate through the entire collection each time, which is going to be unnecessarily slow. 另外,您的代码和其他答案每次都遍历整个集合,这将不必要地变慢。 You should use a dictionary for quick lookups, (unless, of course, there are frequent changes to the Users collection which makes caching impossible). 您应该使用字典进行快速查找(当然,除非对Users集合进行频繁更改,否则将无法进行缓存)。

Example: 例:

class MyClass
{
    private Dictionary<String,User> _userLookup;

    public MyClass()
    {
        _userLookup = Context.Users.ToDictionary(u => u.UserName.ToLower());
    }

    private User getUserByName(String name)
    {
        var lowerName = name.ToLower();
        return _userLookup.ContainsKey(lowerName) ? _userLookup[lowerName] : null;
    }     
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM