7wp*_*7wp 209 .net c# 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)
return null;
//Should I be doing this here instead?
//return new UserEntity();
else
return existingUserEntity;
}
Run Code Online (Sandbox Code Playgroud)
让我们假设在这个程序中有效的案例,数据库中没有该GUID的用户信息.我想在这种情况下抛出异常是不合适的?此外,我的印象是异常处理可能会损害性能.
ljs*_*ljs 207
如果您打算表明没有可用数据,则返回null通常是最好的想法.
空对象意味着返回了数据,而返回null则清楚地表明没有返回任何内容.
此外,如果您尝试访问对象中的成员,则返回null将导致null异常,这对于突出显示错误代码非常有用 - 尝试访问任何成员都没有意义.访问空对象的成员不会失败意味着错误可能未被发现.
Rex*_*x M 44
这取决于对你的案件最有意义的东西.
返回null是否有意义,例如"没有这样的用户存在"?
或者创建默认用户是否有意义?当你可以安全地假设如果用户不存在时,这就是最有意义的,调用代码打算在他们要求时存在一个.
或者,如果调用代码要求具有无效ID的用户,则抛出异常(la"FileNotFound")是否有意义?
然而 - 从关注点分离/ SRP的角度来看,前两个更正确.从技术上讲,第一个是最正确的(但只有一个头发) - GetUserById应该只负责一件事 - 获取用户.通过返回其他内容来处理自己的"用户不存在"案例可能违反了SRP.bool DoesUserExist(id)如果您选择抛出异常,则分成不同的检查是合适的.
基于以下广泛的评论:如果这是一个API级设计问题,这种方法可能类似于"OpenFile"或"ReadEntireFile".我们从一些存储库"打开"用户并从结果数据中保存对象.在这种情况下,例外可能是适当的.它可能不是,但它可能是.
所有方法都是可以接受的 - 它只取决于API /应用程序的更大上下文.
Dar*_*rov 27
如果返回类型是数组,则返回一个空数组,否则返回null.
Hen*_*man 12
如果特定合同被破坏,您应该抛出异常(仅限).
在您的具体示例中,根据已知的Id请求UserEntity,如果缺少(已删除)用户是预期的案例,则将取决于事实.如果是,则返回null但如果不是预期的情况则抛出异常.
请注意,如果调用该函数,UserEntity GetUserByName(string name)它可能不会抛出但返回null.在这两种情况下,返回一个空的UserEntity将是无益的.
对于字符串,数组和集合,情况通常是不同的.我记得一些指南形式的MS,方法应该接受null为"空"列表,但返回零长度的集合而不是null.字符串相同.请注意,您可以声明空数组:int[] arr = new int[0];
Cha*_*ana 11
这是一个业务问题,取决于具有特定Guid Id的用户是否是此功能的预期正常用例,或者是否会阻止应用程序成功完成此方法为用户提供的任何功能的异常反对...
如果它是一个"例外",因为缺少具有该Id的用户将阻止应用程序成功完成它正在执行的任何功能,(假设我们正在为客户创建发票,我们已将产品发送到... ),那么这种情况应该抛出ArgumentException(或其他一些自定义异常).
如果缺少用户没问题,(调用此函数的潜在正常结果之一)则返回null ....
编辑:(在另一个答案中解决亚当的评论)
如果应用程序包含多个业务流程,其中一个或多个需要用户才能成功完成,并且其中一个或多个业务流程可以在没有用户的情况下成功完成,那么异常应该在调用堆栈中进一步抛出,更靠近哪里需要用户的业务流程正在调用此执行线程.此方法与该点(抛出异常)之间的方法应该只传达没有用户存在(null,boolean,无论什么 - 这是一个实现细节).
但是如果应用程序中的所有进程都需要用户,我仍然会在此方法中抛出异常......
Ale*_*ore 10
我个人会返回null,因为这就是我期望DAL/Repository层行动的方式.
如果它不存在,不要返回任何可以被解释为成功获取对象的东西,null在这里工作得很漂亮.
最重要的是要在你的DAL/Repos Layer中保持一致,这样你就不会对如何使用它感到困惑.
我倾向于
return null如果当它不知道它是否事前对象ID不存在应存在.throw如果对象id在它应该存在时不存在.我用这三种方法区分这两种情况.第一:
Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
if (InternalIdExists(id))
{
o = InternalGetSomeObject(id);
return true;
}
else
{
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
第二:
SomeObject FindSomeObjectById(Int32 id)
{
SomeObject o;
return TryGetObjectById(id, out o) ? o : null;
}
Run Code Online (Sandbox Code Playgroud)
第三:
SomeObject GetSomeObjectById(Int32 id)
{
SomeObject o;
if (!TryGetObjectById(id, out o))
{
throw new SomeAppropriateException();
}
return o;
}
Run Code Online (Sandbox Code Playgroud)
另一种方法涉及传入将对值进行操作的回调对象或委托.如果未找到值,则不会调用回调.
public void GetUserById(Guid id, UserCallback callback)
{
// Lookup user
if (userFound)
callback(userEntity); // or callback.Call(userEntity);
}
Run Code Online (Sandbox Code Playgroud)
当您希望避免在代码中进行空检查时,以及在未找到值时不是错误,这种方法很有效.如果您需要任何特殊处理,也可以在没有找到对象时提供回调.
public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
// Lookup user
if (userFound)
callback(userEntity); // or callback.Call(userEntity);
else
notFound(); // or notFound.Call();
}
Run Code Online (Sandbox Code Playgroud)
使用单个对象的相同方法可能如下所示:
public void GetUserById(Guid id, UserCallback callback)
{
// Lookup user
if (userFound)
callback.Found(userEntity);
else
callback.NotFound();
}
Run Code Online (Sandbox Code Playgroud)
从设计的角度来看,我真的很喜欢这种方法,但是它的缺点是使得呼叫站点在不易支持一流功能的语言中变得更加庞大.