Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.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#方法_C# - Fatal编程技术网

采用单个项目或列表的C#方法

采用单个项目或列表的C#方法,c#,C#,我有一个方法,现在只需要一个id。我需要添加一个获取ID列表的方法。我的选择是让其中一个方法调用另一个,如下所示: void NotifyUsers(List<int> userIds) {//do things} void NotifyUser(int userId) { NotifyUsers(new List<int>{userId}) } void NotifyUsers(列出用户ID){//do things} void NotifyUser(int u

我有一个方法,现在只需要一个id。我需要添加一个获取ID列表的方法。我的选择是让其中一个方法调用另一个,如下所示:

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

void NotifyUser(int userId)
{
  NotifyUsers(new List<int>{userId})
}
void NotifyUsers(列出用户ID){//do things}
void NotifyUser(int userId)
{
NotifyUsers(新列表{userId})
}
或者我可以将调用更改为
NotifyUsers(新列表{9999}

或者我可以使用泛型,等等

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


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

如果可以使用数组代替特定的
列表,则可以使用。例如:

void NotifyUsers(params int[] userIds)
{
    //...
}
可以使用零个或多个参数调用:

NotifyUsers(123);
NotifyUsers(5, 67, 890);
// etc.
这里的“最佳实践”是什么

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

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

// 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);
}
在这种情况下,我将添加第三个函数:

void NotifyUsers(params int[] ids)
{
  NotifyUsers((IEnumerable<int>) ids);
}
这说明了一个重要的问题:考虑调用者的需求还包括对你不认识的人进行心理分析,找出他们会做错什么,然后在错误发生之前加以预防。设计让人们自然而然只会成功的API是很困难的

(另外,请注意,这些草图忽略了错误处理;您可能希望检查序列和数组是否不为null,以此类推。)

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

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

  • “一次”通知一百个用户并不比一次通知一百个用户更有效
  • 如果在一个序列中通知一个用户失败,正确的做法是停止再通知
如果这些假设是错误的?考虑一个更新数据库的API,而昂贵的部分不是更新,而是连接到数据库。在这种情况下,你不想写:

void NotifyUser(int id) 
{
  Connect(); // Expensive
  Update(id);
  Disconnect();
}
void NotifyUsers(IEnumerable<int> ids)
{
  foreach(var id in ids)
    NotifyUser(id);
}
void NotifyUser(int-id)
{
Connect();//昂贵
更新(id);
断开连接();
}
void NotifyUsers(IEnumerable ID)
{
foreach(id中的变量id)
通知用户(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();
}
void NotifyUser(int-id)
{
NotifyUsers(可枚举。重复(id,1));
}
void NotifyUsers(IEnumerable ID)
{
Connect();
foreach(id中的变量id)
更新(id);
断开连接();
}
请注意,在重写实现时,我没有重写API;请记住,我们已经将API设计为适合调用方,因此如果此API满足调用方的需求,请不要更改它!方法是抽象的;我们可以更改细节以满足性能要求。(如果我们因为API设计问题而无法达到性能目标,那么我们首先就没有设计出满足调用方需求的API。)

那么现在如何处理错误呢?有多种可能性:

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

以此类推。再次仔细考虑打电话者的需求。他们期望失败时会发生什么?你知道如何编写逻辑来实现打电话者的期望吗?你能清楚地记录它,以便打电话者知道他们的期望是否得到满足吗?

也许你在寻找关键词?为什么需要一段时间特别是列表?这意味着您不能向方法传递数组、查询或任何其他序列。您对列表做了什么,要求它特别是列表?您是在尝试对
userIds
中的每个项做些什么,还是对集合作为一个整体做些什么?@EricLippert它肯定不需要o以列表为例-任何
IEnumerable
都可以。@TylerHundley在这种特殊情况下,我通过Mailkit的SMTP传递一个电子邮件对象并异步发送电子邮件。我只是举了一个简单的例子,因为我认为它不相关。OP明确要求提供一个
IEnumerable
,所以它宁愿是
NotifyUsers(list.ToArray())
@JanWichelmann:原始海报在评论中还说,他们实际上希望接受任何序列,而不仅仅是列表。这似乎就是我要寻找的-我不知道params关键字…真丢脸。@EricLippert是的,这是我发表评论时的种族条件;)不过,
ToArray
应该可以做到这一点。我已经编辑了注释,但是编辑答案可能是可取的。这听起来像是第二节课,也就是使用最简单的类型只支持方法签名中真正必要的功能。(例如,当需要枚举集合的能力时,使用
IEnumerable
而不是
List
)接受这一完整性。感谢大家的帮助。在使用
params
关键字的方法中,是否真的需要此强制转换:
NotifyUsers((IEnumerable)id)
?ids
是否已经是一个
IEnumerable
?@Lu
void NotifyUser(int id) 
{
  Connect(); // Expensive
  Update(id);
  Disconnect();
}
void NotifyUsers(IEnumerable<int> ids)
{
  foreach(var id in ids)
    NotifyUser(id);
}
void NotifyUser(int id) 
{
  NotifyUsers(Enumerable.Repeat(id, 1));
}
void NotifyUsers(IEnumerable<int> ids)
{
  Connect();
  foreach(var id in ids)
    Update(id);
  Disconnect();
}