从函数返回数据的最佳实践是什么?是返回Null对象好还是返回空对象好?为什么要选择一种而不是另一种呢?

考虑一下:

public UserEntity GetUserById(Guid userId)
{
     //Imagine some code here to access database.....

     //Check if data was returned and return a null if none found
     if (!DataExists)
        return null; 
        //Should I be doing this here instead? 
        //return new UserEntity();  
     else
        return existingUserEntity;
}

让我们假设在这个程序中存在有效的情况,即数据库中没有具有该GUID的用户信息。我认为在这种情况下抛出异常是不合适的??另外,我的印象是异常处理会损害性能。


当前回答

如果用户没有被找到的情况经常出现,你想要根据情况以各种方式处理(有时抛出异常,有时替换一个空用户),你也可以使用接近f#的Option或Haskell的Maybe类型,它显式地将“无值”情况与“发现了一些东西!”数据库访问代码看起来像这样:

public Option<UserEntity> GetUserById(Guid userId)
{
 //Imagine some code here to access database.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return Option<UserEntity>.Nothing; 
 else
    return Option.Just(existingUserEntity);
}

并且像这样使用:

Option<UserEntity> result = GetUserById(...);
if (result.IsNothing()) {
    // deal with it
} else {
    UserEntity value = result.GetValue();
}

不幸的是,每个人似乎都有自己喜欢的类型。

其他回答

异步TryGet模式:

对于同步方法,我相信@Johann Gerell的回答是适用于所有情况的模式。

但是带有out参数的TryGet模式不适用于Async方法。

使用c# 7的元组文字,你现在可以这样做:

async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

        return (true, o);
    }
    else
    {
        return (false, default(SomeObject));
    }
}

我通常返回null。它提供了一种快速而简单的机制来检测是否出现了错误,而不会抛出异常,也不会到处使用大量的try/catch。

如果您打算表示没有可用的数据,返回null通常是最好的主意。

空对象表示已返回数据,而返回null则明确表示没有返回任何数据。

此外,如果试图访问对象中的成员,返回null将导致null异常,这对于突出显示有bug的代码很有用——试图访问没有任何成员的成员是没有意义的。访问空对象的成员不会失败,这意味着bug不会被发现。

我个人返回该对象的默认实例。原因是我希望该方法返回0到多或0到1(取决于该方法的目的)。使用这种方法,它将是任何类型的错误状态的唯一原因是,如果方法不返回任何对象,并且总是期望返回(就一对多或单数返回而言)。

至于假设这是一个业务领域的问题——我只是没有从等式的那一边看到它。返回类型的规范化是一个有效的应用程序体系结构问题。至少,它是编码实践标准化的主题。我怀疑是否有业务用户会说“在场景X中,只给他们一个null”。

(仅)在特定契约被破坏时抛出异常。 在您的特定示例中,请求基于已知Id的UserEntity,这将取决于丢失(删除)用户是否是预期情况。如果是,则返回null,但如果不是预期的情况,则抛出异常。 注意,如果函数名为UserEntity GetUserByName(字符串名),它可能不会抛出而是返回null。在这两种情况下,返回空的UserEntity都没有帮助。

对于字符串、数组和集合,情况通常是不同的。我记得MS的一些指导原则,方法应该接受null作为一个“空”列表,但返回零长度的集合而不是null。字符串也是一样。注意,你可以声明空数组:int[] arr = new int[0];