Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/14.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# 函数应该返回null还是空对象?_C#_.net_Function_Return Value - Fatal编程技术网

C# 函数应该返回null还是空对象?

C# 函数应该返回null还是空对象?,c#,.net,function,return-value,C#,.net,Function,Return Value,从函数返回数据时的最佳实践是什么。返回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)

从函数返回数据时的最佳实践是什么。返回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的用户信息。我认为在这种情况下抛出异常是不合适的??另外,我的印象是,异常处理可能会影响性能。

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

空对象表示已返回数据,而返回null则明确表示未返回任何内容


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

这取决于什么对您的情况最有意义

返回null是否有意义,例如“不存在这样的用户”

或者创建默认用户有意义吗?当您可以安全地假设用户不存在时,调用代码希望用户在请求时存在时,这是最有意义的

或者,如果调用代码要求用户使用无效ID,抛出异常(la“FileNotFound”)是否有意义

然而,从关注点分离/SRP的角度来看,前两个更为正确。从技术上讲,第一个是最正确的(但只需要一根头发)——GetUserById应该只负责一件事——获取用户。通过返回其他内容来处理自己的“用户不存在”案例可能违反SRP。如果您选择抛出异常,则将其分离为不同的检查-
bool doesurexist(id)
是合适的

基于下面的大量评论:如果这是一个API级设计问题,此方法可能类似于“OpenFile”或“ReadEntRefile”。我们正在从某个存储库“打开”一个用户,并从生成的数据中水合该对象。在这种情况下,例外情况可能是合适的。可能不是,但可能是


所有方法都是可以接受的——这取决于API/应用程序的更大上下文

我个人会返回null,因为我希望DAL/存储库层会这样做

如果它不存在,不要返回任何可能被解释为成功获取对象的内容,
null
在这里工作得很好


最重要的是在DAL/Repos层上保持一致,这样您就不会对如何使用它感到困惑。

这是一个业务问题,取决于具有特定Guid Id的用户是否是此功能的预期正常用例,或者这是一种异常现象,它会阻止应用程序成功完成此方法向用户对象提供的任何功能

如果它是一个“异常”,即缺少具有该Id的用户将阻止应用程序成功完成其正在执行的任何功能(例如,我们正在为我们将产品运送到的客户创建发票…),那么这种情况应该引发ArgumentException(或其他一些自定义异常)

如果缺少的用户是ok(调用此函数的潜在正常结果之一),则返回null

编辑:(在另一个答案中回答亚当的评论)

如果应用程序包含多个业务流程,其中一个或多个业务流程需要用户才能成功完成,并且其中一个或多个业务流程可以在没有用户的情况下成功完成,则应在调用堆栈的更上层引发异常,更接近需要用户的业务流程调用此执行线程的位置。这个方法和那个点(抛出异常的地方)之间的方法应该只传递不存在用户的信息(null、boolean等等,这是一个实现细节)


但是如果应用程序中的所有进程都需要一个用户,我仍然会在这个方法中抛出异常

它会根据上下文而变化,但如果我在寻找一个特定对象(如您的示例中),通常会返回null,如果我在寻找一组对象但没有,则返回空集合


如果您在代码中犯了一个错误,并且返回null会导致null指针异常,那么越早发现越好。如果返回一个空对象,最初使用它可能有效,但以后可能会出现错误。

我个人使用NULL。它清楚地表明没有要返回的数据。但在某些情况下,a可能是有用的。

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

如果返回类型是数组,则返回空数组,否则返回null。

在这种情况下,如果没有这样的用户,最好返回“null”。还要使您的方法保持静态

编辑:


通常,像这样的方法是某些“用户”类的成员,没有访问其实例成员的权限。在这种情况下,该方法应该是静态的,否则必须创建一个“User”实例,然后调用GetUserById方法,该方法将返回另一个“User”实例。我同意这令人困惑。但是,如果GetUserById方法是某个“DatabaseFactory”类的成员,那么将其保留为实例成员是没有问题的。

如果某个特定的约定被破坏,您应该(仅)抛出一个异常。
在您的特定示例中,根据已知Id请求UserEntity,这将取决于缺少(删除)用户是否为预期情况。如果是,则返回
null
,但如果是
// Returns null if user does not exist
public UserEntity GetUserById(Guid userId)
{
}

// Returns a New User if user does not exist
public UserEntity GetNewOrExistingUserById(Guid userId)
{
}
public UserEntity GetUserById(Guid userId)
 //Check if data was returned and return a null if none found
 if (!DataExists)
    return new NullUserEntity(); //Should I be doing this here instead? return new UserEntity();  
 else
    return existingUserEntity;
class NullUserEntity: IUserEntity { public string getFirstName(){ return ""; } ...} 
if (User.Exists(id)) { this.User = User.Fetch(id); } else { Response.Redirect("~/notfound.aspx"); } this.User = User.Fetch(id); if (this.User == null) { Response.Redirect("~/notfound.aspx"); }
function saveTheRow($prim_key, $data) {
    $row = getRowByPrimKey($prim_key);

    // Populate the data here

    $row->save();
}
function displayData($row_id) {
    // Logging of the error would happen in this function
    $row = getRow($row_id);
    if($row === null) {
        // Handle the error here
    }

    // Do stuff here with data
}

function getRow($row_id) {
 $row = null;
 try{
     if(!$db->connected()) {
   throw excpetion("Couldn't Connect");
  }

  $result = $db->query($some_query_using_row_id);

  if(count($result) == 0 ) {
   throw new exception("Couldn't find a record!");
  }

  $row = $db->nextRow();

 } catch (db_exception) {
  //Log db conn error, alert admin, etc...
  return null; // This way I know that null means an error occurred
 }
 return $row;
}
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();
}
bool IsAdministrator(User user)
{
    var groupsOfUser = GetGroupsOfUser(user);

    // This foreach would cause a run time exception if groupsOfUser is null.
    foreach (var groupOfUser in groupsOfUser) 
    {
        if (groupOfUser.Name == "Administrators")
        {
            return true;
        }
    }

    return false;
}
public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
}
public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
    else
        notFound(); // or notFound.Call();
}
public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback.Found(userEntity);
    else
        callback.NotFound();
}
Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
    if (InternalIdExists(id))
    {
        o = InternalGetSomeObject(id);

        return true;
    }
    else
    {
        return false;
    }
}
SomeObject FindSomeObjectById(Int32 id)
{
    SomeObject o;

    return TryGetObjectById(id, out o) ? o : null;
}
SomeObject GetSomeObjectById(Int32 id)
{
    SomeObject o;

    if (!TryGetObjectById(id, out o))
    {
        throw new SomeAppropriateException();
    }

    return o;
}
foreach (var eachValue in collection ?? new List<Type>(0))
async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

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