首页 > 解决方案 > 采用单个项目或列表的 C# 方法

问题描述

我有一个方法现在需要一个 id。我需要添加一个采用 id 列表的方法。我的选择是让其中一种方法像这样调用另一种方法:

void NotifyUsers(List<int> userIds) {//do things}

void NotifyUser(int userId)
{
  NotifyUsers(new List<int>{userId})
}

或者我可以将呼叫更改为NotifyUsers(new List<int>{9999}.

或者我可以使用泛型等。

这里的“最佳实践”是什么?

我知道这有点基于意见的问题,但似乎应该有一个围绕这个的标准,但我找不到它。

标签: c#

解决方案


这里的“最佳实践”是什么?

最佳做法是采用整体方法,特别强调调用者的需求。这并不一定意味着为调用者提供最大的灵活性!这意味着了解调用者的用例。

我个人构建此解决方案的方式是:

// Notice: User, not Users. This notifies a single user.
void NotifyUser(int id) 
{
  // notify the user
}

void NotifyUsers(IEnumerable<int> ids)
{
  foreach(var id in ids) 
    NotifyUser(id);
}

这向调用者强调,如果您想执行一次,请使用NotifyUser,并且如果您有任何用户序列(不仅仅是列表),那么您NotifyUsers使用该序列进行调用。

现在我要问的下一个问题是:调用者是否想要这样做:

NotifyUsers(10, 20, 30);

在这种情况下,我会添加第三个函数:

void NotifyUsers(params int[] ids)
{
  NotifyUsers((IEnumerable<int>) ids);
}

这种技术对调用者来说是灵活的,同时确保您的大多数方法都是简单的单行方法。如果 NotifyUser 中存在错误,您只想在一个地方修复它。

这种方法的一个缺点是它NotifyUsers()变得合法并且是无操作的。有人可能会不小心调用它并认为它正在做某事。在这种情况下,您可能会强制至少有一个:

void NotifyUsers(int id, params int[] ids)
{
  NotifyUser(id);
  NotifyUsers((IEnumerable<int>) ids);
}

这说明了一个重要的观点:考虑来电者的需求还涉及对你不认识的人进行心理分析,以找出他们会做错什么,然后在它发生之前阻止它。设计让人们自然而然地走向成功的 API很难

(另外,请注意这些草图省略了错误处理;您可能想要检查序列和数组是否不为空,等等。)

这里的关键是:从了解调用者的需求开始;设计满足他们需求的 API。然后实施它。也就是说,实施选择应该是什么?

这取决于通知一系列用户的工作方式。我上面勾勒的解决方案做了一些假设。他们是:

  • “一次”通知一百个用户并不比一次通知一百个用户更有效
  • 如果按顺序通知一个用户失败,正确的做法是停止再通知。

如果这些假设是错误的怎么办?考虑一个更新数据库的 API,昂贵的部分不是更新,而是与数据库建立连接。在这种情况下,您不想写:

void NotifyUser(int id) 
{
  Connect(); // Expensive
  Update(id);
  Disconnect();
}
void NotifyUsers(IEnumerable<int> ids)
{
  foreach(var id in ids)
    NotifyUser(id);
}

因为现在您正在为 100 个用户建立 100 个连接。相反,您想翻转脚本:

void NotifyUser(int id) 
{
  NotifyUsers(Enumerable.Repeat(id, 1));
}
void NotifyUsers(IEnumerable<int> ids)
{
  Connect();
  foreach(var id in ids)
    Update(id);
  Disconnect();
}

请注意,在重写实现时,我没有重写 API;请记住,我们已经为调用者设计了 API ,因此如果此 API 满足他们的需求,请不要更改它!方法是抽象;我们可以更改细节以满足性能要求。(如果我们因为 API 设计问题而无法达到性能目标,那么我们一开始就没有设计满足调用者需求的 API。)

现在错误处理呢?有很多可能性:

  • 通知需要尽最大努力。如果序列中的一个通知失败,则捕获异常,吃掉它,然后继续与其他用户一起工作。永远不要通知调用者失败
  • 通知需要尽最大努力,但调用者需要了解所有故障。记录异常并重新抛出它们或返回失败报告而不是 void。
  • 通知必须是全有或全无。也就是说,如果第十个通知失败,则撤消之前的通知以保持世界一致。这很难。你不能解铃。

等等。再次仔细考虑调用者的需求。他们期望失败时会发生什么?你知道如何编写逻辑来做调用者期望的事情吗?您能否清楚地记录下来,以便调用者知道他们的期望是否得到满足?


推荐阅读