![](/img/trans.png)
[英]C# thread locking and using a lock object; what should the correct scope be for the lock object?
[英]Correct scope of using using
我正和一位同事討論使用聲明的適當范圍。 這是有問題的方法。
public Guid IsServerReachable()
{
try
{
WhoAmIResponse whoAmI;
using (OrganizationServiceProxy service = GetService())
whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
return whoAmI.UserId;
}
catch { return Guid.Empty; }
}
我們中的一個人聲稱using語句應該包含whyAmI的聲明,而另一個聲明它只是需要使用的服務實例。 我不是說我的理論是哪一個,但顯然是錯誤的。 哪一個?
兩者都是正確的。 我傾向於寫這個:
public Guid IsServerReachable()
{
try
{
using (OrganizationServiceProxy service = GetService())
{
WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
return whoAmI.UserId;
}
}
catch { return Guid.Empty; }
}
這對whoAmI
是否被處置沒有任何影響 - 唯一被自動處理的是service
。
如果WhoAmIResponse
也是IDisposable
,您必須編寫以下內容以自動釋放兩者:
using (OrganizationServiceProxy service = GetService())
using (WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse)
return whoAmI.UserId;
由於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
而聲明使用塊內的所有內容:
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
。
這些是非常罕見的情況(EDIT:應該注意的是,get-access副作用和Dispose()
拋出異常都被視為不良行為),我建議如果是這種情況,那么你應該考慮這些是正確的。 如果這些都不是問題(沒有副作用,也不關心訪問/處置的順序),那么從長遠來看,使用您和您的團隊認為更易於維護/可讀的內容。
using
語句必須包含語句終止時應該處理的對象的聲明。 只要OrganizationServiceProxy
實現IDisposable
而WhoAmIResponse
不實現,您的代碼就是正確的。
如有疑問,將using塊重寫為try-finally塊通常很有用:
OrganizationServiceProxy service = GetService();
try {
whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
} finally {
service.Dispose();
}
最佳實踐是任何using
語句的范圍盡可能小。 只要在運行Dispose
方法時, OrganizationServiceProxy
返回的對象不會被Dispose
,指定的范圍就完全可以接受了。
using (OrganizationServiceProxy service = GetService())
whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
將相當於:
OrganizationServiceProxy service = GetService();
try
{
whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse;
}
finally
{
if (myRes!= null)
// Call the object's Dispose method.
((IDisposable)service).Dispose();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.