C# 结果对象而不是输出参数
我的一位同事提出了一个有趣的想法,但我们都有点不确定可能出现的复杂情况 目前,我们的大多数方法都有一个“out”参数来返回消息列表(成功、错误等)。就像这样C# 结果对象而不是输出参数,c#,asp.net,generics,error-handling,out,C#,Asp.net,Generics,Error Handling,Out,我的一位同事提出了一个有趣的想法,但我们都有点不确定可能出现的复杂情况 目前,我们的大多数方法都有一个“out”参数来返回消息列表(成功、错误等)。就像这样 public bool Delete(int id, out List<UIMessage> uiMessages) { //Delete stuff bool wasDeleteSuccessful = //set bool here List<UIMessages> uiMessages
public bool Delete(int id, out List<UIMessage> uiMessages)
{
//Delete stuff
bool wasDeleteSuccessful = //set bool here
List<UIMessages> uiMessages = //Set messages here
return wasDeleteSuccessful
}
public ResultObject<bool> Delete(int id)
{
//Delete stuff
bool wasDeleteSuccessful = //set bool here
List<UIMessages> uiMessages = //Set messages here
return new ResultObject<bool>(wasDeleteSuccessful, uiMessages)
}
public bool Delete(int-id,out-List-uiMessages)
{
//删除内容
bool wasDeleteSuccessful=//在此处设置bool
List uiMessages=//在此处设置消息
返回成功
}
我们正在考虑返回一个新对象的想法,该对象将具有T类型属性和列表属性。就像这样
public bool Delete(int id, out List<UIMessage> uiMessages)
{
//Delete stuff
bool wasDeleteSuccessful = //set bool here
List<UIMessages> uiMessages = //Set messages here
return wasDeleteSuccessful
}
public ResultObject<bool> Delete(int id)
{
//Delete stuff
bool wasDeleteSuccessful = //set bool here
List<UIMessages> uiMessages = //Set messages here
return new ResultObject<bool>(wasDeleteSuccessful, uiMessages)
}
公共结果对象删除(int-id)
{
//删除内容
bool wasDeleteSuccessful=//在此处设置bool
List uiMessages=//在此处设置消息
返回新的ResultObject(wasDeleteSuccessful,uiMessages)
}
我敢肯定,这里唯一的好处是我们不必处理“out”参数,但我们没有考虑哪些缺点?没有主要缺点,只是新的结果对象不必要的额外复杂性,它包含与先前使用
out
参数实现完全相同的信息。如果这些方法被大量执行,那么(性能和内存方面)您可能会更好地使用更少的对象进行实例化,从而使用第一个(out)实现
我个人更喜欢给定示例中的out实现,因为您的方法倾向于遵循。Try parse模式通过返回bool来通知您成功,并为您提供result/info对象in-out参数。在这种情况下,您的命名有点错误。与其删除,不如将方法命名为TryDelete通常最好返回值,而不是变异变量。通过返回值而不是变异变量,您可以在不能变异变量的上下文中使用方法。例如,删除是异步的主要候选,因为它可能是一个高延迟操作。改变调用方变量的方法很难实现异步 然而,这将是一个很好的时间退一步,问问你是否真的在做正确的事情摆在首位。这种方法的合同似乎很奇怪。我希望删除某些内容的方法返回void,因为删除是一种效果,而不是值的产生。我希望在发生故障时,故障状态将存储在抛出的异常中,而不是消息列表中 查看为该问题提供解决方案的NuGet包(需要.NET标准2) 它的核心是
IDomainResult
(类似于您的ResultObject
),具有以下属性:
IReadOnlyCollection Errors{get;}//错误消息的集合(如果有)
bool issucess{get;}//标志,当前状态是否成功
DomainOperationStatus状态{get;}//域操作的当前状态:成功、错误、未找到
从这里开始,在方法中有两个返回对象的选项:
IDomainResult
,它通过添加T值{get;}
属性来扩展上述结果(T,IDomainResult)
//使用int的成功结果
(值,状态)=IDomainResult.Success(10);//数值=10;状态。状态为“成功”
//相同,但包装在一个任务中
var res=IDomainResult.SuccessTask(10);//res是任务
//错误消息
IDomainResult=IDomainResult.Error(“啊!”);//res.状态为'Error',res.Errors=new[]{“Ahh!”}
//应为int时出错
(值,状态)=IDomainResult.Error(“啊!”);//value=0,state.Status为'Error'和state.Errors=new[]{“Ahh!”}
例如:
公共异步任务GetInvoice(int invoiceId)
{
如果(发票ID<0)
//返回验证错误
返回IDomainResult.Error(“更加努力”);
var invoice=wait DataContext.Invoices.FindAsync(invoiceId);
如果(发票==null)
//返回未找到的响应
返回IDomainResult.NotFound();
//返回发票
IDomainResult.Success(发票);
}
或者,如果您反对,则使用更传统的方法签名:
公共异步任务GetInvoice(int invoiceId)
{
如果(发票ID<0)
//返回验证错误
返回DomainResult.Error(“更加努力”);
...
}
它还有20多个扩展,用于将基于IDomainResult
的类型转换为相应的IActionResult
,以便从WebAPI控制器方法返回
请在查看样品。这都是你的主意。这个主意并不新鲜。检查实现和用例。考虑到
List
是一种引用类型,调用方可以安全地传入一个初始化的实例,然后该方法将添加到该实例中。只是另一种选择。@PoweredByOrange哦,对了。。。这是有道理的,人们可以使用out
参数,有些则不行。我想说,这只是一种更干净的方式来做你已经在做的事情。我不会把这主要是基于意见的,因为它会问潜在的问题,但请记住,你的问题有点抽象。@ USE2020116我会说是一个更合适的姐妹网站,关于软件设计实践的问题。我不认为奇怪的是,删除方法返回BoOL;这种方法在集合中很常见(例如,因为用户只关心集合排除了对象,而不关心对象是否被删除。这种方法在并发集合中也很常见。@EricLippert如果删除失败是常见的(不是例外)在这种情况下,您是否仍然建议使用异常或可能返回带有失败原因的对象?我这样说是因为我越来越多地看到人们使用EXE的“趋势”