簡體   English   中英

正確使用范圍

[英]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實現IDisposableWhoAmIResponse不實現,您的代碼就是正確的。

如有疑問,將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM