当方法具有多个退出点时,我试图找出跟踪方法返回值的最佳方法。我有几十种方法要添加跟踪。我会通过我尝试过的。
首先,我尝试将每个方法重构为具有这样的单个退出点:
StatusCode CreateResource(string name, string type)
{
Trace.LogEvent("BEGIN CreateResource name=" + name + " type=" + type);
StatusCode status = StatusCode.Ok;
if (!IsValidResourceName(name))
status = StatusCode.InvalidName;
else
{
if (!IsValidResourceType(type))
status = StatusCode.InvalidType;
else
{
if (!SystemOnline())
status = StatusCode.SystemOffline;
//continues to nest with more conditions
}
}
Trace.LogEvent("END CreateResource result=" + status);
return status;
}
但是嵌套的 if 语句使它变得丑陋且可读性降低。我大量使用早期退出点作为保护语句,重构它只会造成一团糟,感觉就像解重构。
我尝试的另一件事是将每个方法包装在另一个跟踪返回值的方法中:
StatusCode CreateResource(string name, string type)
{
Trace.LogEvent("BEGIN CreateResource name=" + name + " type=" + type);
StatusCode status = CreateResource_DONT_CALL_THIS_METHOD(name, type);
Trace.LogEvent("END CreateResource result=" + status);
return status;
}
StatusCode CreateResource_DONT_CALL_THIS_METHOD(string name, string type)
{
if (!IsValidResourceName(name))
return StatusCode.InvalidName;
if (!IsValidResourceType(type))
return StatusCode.InvalidType;
if (!SystemOnline())
return StatusCode.SystemOffline;
return StatusCode.Ok;
}
问题是如何防止将来其他开发人员(或我)调用包装方法并绕过跟踪,因此包装方法的名称荒谬(且矛盾)。我可以为内部方法定义和调用匿名方法,但这是一个在整个项目中使用的非常混乱的模式。
我发现的最可靠、最易读的方法是这样的,这在 IMO 中还可以,但我怀疑这种 for 语句的使用是否会在代码审查中发挥作用:
StatusCode CreateResource_Internal(string name, string type)
{
Trace.LogEvent("BEGIN CreateResource name=" + name + " type=" + type);
StatusCode status = StatusCode.Ok;
for (int i = 0; i < 1; i++)
{
if (!IsValidResourceName(name))
{
status = StatusCode.InvalidName;
break;
}
if (!IsValidResourceType(type))
{
status = StatusCode.InvalidType;
break;
}
if (!SystemOnline())
{
status = StatusCode.SystemOffline;
break;
}
}
Trace.LogEvent("END CreateResource result=" + status);
return status;
}
我使用 try finally 块尝试了一个变体:
StatusCode CreateResource_Internal(string name, string type)
{
Trace.LogEvent("BEGIN CreateResource name=" + name + " type=" + type);
StatusCode status = StatusCode.Ok;
try
{
if (!IsValidResourceName(name))
{
status = StatusCode.InvalidName;
return status;
}
if (!IsValidResourceType(type))
{
status = StatusCode.InvalidType;
return status;
}
if (!SystemOnline())
{
status = StatusCode.SystemOffline;
return status;
}
}
finally
{
Trace.LogEvent("END CreateResource result=" + status);
}
return StatusCode.Ok;
}
这里的缺点是在返回之前可能会忘记设置“状态”变量,在这种情况下将不会执行跟踪。
我的问题是,是否有这样做的最佳实践?我是否应该重构为单个退出点?是否有某种方法可以防止从其他地方调用包装的方法?允许绕过跟踪的危险是否比重构到单个出口点的不整洁更糟糕?
ps 我不想引入像面向方面编程这样繁重的东西。