如果在找不到值时为非null,则应该返回什么

时间:2012-03-03 17:40:51

标签: c# null return-value

我读到的每个地方都不断重写“永远不会返回空值”的想法,但如果在找不到值的情况下,如果不为null,我应该返回什么?

采取以下方法

List<Customer> GetCustomerListByRoleID(Guid RoleID) {}

在这种情况下(在大多数复数方法中)如果我们找不到我们的价值并且我们很好,那么很容易简单地返回一个空的List<Customer>

但是在类似

的方法的情况下
Customer GetCustomerByID(Guid CustomerID) {}

你没有返回空数组的奢侈。事实上你所能做的就是返回一个New Customer();,但是你有一个潜在的未初始化对象(你仍需要检查)或null。

那么在单数方法中返回null的推荐替代方法是什么?

4 个答案:

答案 0 :(得分:10)

对于单值情况,请考虑TryGet模式

bool TryGetCustomerByID(Guid CustomerID, out Customer customer) { }

这清楚地表达了这种方法能够并且将会失败的意图,并使忽略失败方面更加尴尬。正确处理它会产生非常易读的代码。

Customer c;
if (container.TryGetCustomer(id, out c)) {
  ...
} else {
  // Deal with failure
}

我经常喜欢将我的TryGet API与在调用者知道时必须存在的那些场合抛出的版本配对,否则它违反了某些隐式契约。

Customer GetCustomerByID(Guid id) {
  Customer c;
  if (!TryGetCustomerByID(id, out c)) {
    throw new Exception(...);
  }
  return c;
}

答案 1 :(得分:0)

我认为这取决于是否应该将不存在的客户视为错误。两个明显的选择是:

  • 返回null
  • 抛出异常(CustomerNotFoundException或类似的东西)

在您获得Guid的情况下,感觉就像代表客户的明确期望一样。尝试使用 offchance 上的Guid来获取客户是不正常的。

可以返回Tuple<Customer, bool>TryGetCustomer - 但说实话,我认为这两种情况都过于复杂。

大多数重要的是你记录会发生什么......特别是,如果你的代码永远不会返回null,请在文档中说明。 (或者考虑使用代码合同来提供相同的信息......)

答案 2 :(得分:0)

您可以定义一个静态Customer对象,该对象表示一个空客户(即Customer.Name =“NOT_FOUND”,并返回该对象而不是null。然后在调用方法中,只需将返回值与该静态客户进行比较。 / p>

编辑:虽然我承认只想返回null。

答案 3 :(得分:0)

为什么不鼓励重新调整null?我们的想法是,如果函数的返回类型为T,则总是会得到一个T类型的对象,而null 肯定是而不是{{1}类型的对象},甚至不是T类型的零对象。

如果是T,则会得到一个getCustomers(),它是0到List<Customer>个对象。

如果是Customer,您需要0或1个getCustomer()个对象。在Haskell中,您获得了ADT和Customer,在Scala中,您有案例类和Maybe。你能在C#中使用什么?嗯,有Maybe implementaion in C#,内部非常简单。

使用Option,您可以保证不将其结果作为空值而不是Maybe<Customer> getCustomer()值传递。您被明确警告:您可以获得客户,也可以不获得客户。

为什么Customer的效果优于Maybe?这是因为null是一个具有良好数学基础的monad,而Maybe则不是。nullList也是一个monad,这就是它如此方便的原因。使用正确的方法monads can be combined in nice ways,这样您就无需在任何地方检查HasValue。对于null,您会遇到每个函数结果的C风格嵌套if

例外也是一个单子!这就是为什么其他答案(正确)建议抛出异常的原因。除了例外,你甚至可以获得另一个典型的函数式编程,即模式匹配(在catch子句中)。