由于whoAmI
在这种情况下,声明在性能/范围方面并没有任何区别。真正归结为是否应该将 的属性访问权限whoAmI.UserId
也包含在using
. 从 IL 的角度来看,两者之间唯一的功能区别OrganizationalServiceProxy.Dispose
是调用方法的顺序和WhoAmIResponse.UserId
访问的时间。
(编辑:我认为如何try/catch
处理返回默认值并没有任何真正的问题,而且这似乎不是问题的一部分,所以这也被省略了)
在您发布的代码中(简化以使 IL 更清晰):
public Guid IsServerReachableOutsideUsingScope()
{
WhoAmIResponse whoAmI;
using(var service = new Service())
whoAmI = service.Execute();
return whoAmI.UserId;
}
在 IL 中的结果:
IL_0000: newobj UserQuery+Service..ctor
IL_0005: stloc.1 // service
IL_0006: ldloc.1 // service
IL_0007: callvirt UserQuery+Service.Execute
IL_000C: stloc.0 // whoAmI
IL_000D: leave.s IL_0019
IL_000F: ldloc.1 // service
IL_0010: brfalse.s IL_0018
IL_0012: ldloc.1 // service
IL_0013: callvirt System.IDisposable.Dispose
IL_0018: endfinally
IL_0019: ldloc.0 // whoAmI
IL_001A: callvirt UserQuery+WhoAmIResponse.get_UserId
IL_001F: ret
而在 using 块中声明所有内容:
public Guid IsServerReachableWithinUsingScope()
{
using(var service = new Service())
{
WhoAmIResponse whoAmI = service.Execute();
return whoAmI.UserId;
}
}
产生 IL:
IL_0000: newobj UserQuery+Service..ctor
IL_0005: stloc.0 // service
IL_0006: ldloc.0 // service
IL_0007: callvirt UserQuery+Service.Execute
IL_000C: stloc.1 // whoAmI
IL_000D: ldloc.1 // whoAmI
IL_000E: callvirt UserQuery+WhoAmIResponse.get_UserId
IL_0013: stloc.2 // CS$1$0000
IL_0014: leave.s IL_0020
IL_0016: ldloc.0 // service
IL_0017: brfalse.s IL_001F
IL_0019: ldloc.0 // service
IL_001A: callvirt System.IDisposable.Dispose
IL_001F: endfinally
IL_0020: ldloc.2 // CS$1$0000
IL_0021: ret
如果在访问属性之前不处理您的服务很重要(例如在 NHibernate 延迟加载的集合的上下文中),那么顺序肯定很重要。如果没关系,那么最大的问题应该是你和你的团队最关心什么。如果你不介意混合和匹配调用,所以有些有大括号,有些没有,那么继续你所拥有的。using
WhoAmIResponse.UserId
如果访问有副作用,可能需要考虑的是异常处理的顺序。如果对您的服务的Dispose
调用引发异常,在您的原始代码 ( IsServerReachableOutsideUsingScope
) 中,它将永远不会访问您的属性,因此永远不会执行其副作用。在第二个代码块 ( IsServerReachableWithinUsingScope
) 中,它将访问并执行使用该UserId
属性的副作用,然后运行Dispose
抛出异常。
这些是相当罕见的情况(编辑:应该注意,获取访问的副作用和Dispose()
抛出异常都被认为是不好的做法),我建议如果是这种情况,那么您应该考虑这些以确保正确性。如果这些不是问题(没有副作用并且不关心访问/处置的顺序),那么从长远来看,使用您和您的团队认为更易于维护/可读的东西。