2013-03-20 6 views
3

나는 의 해당 범위와 관련하여 동료와 다투다. 문을 사용합니다. 이것이 문제의 방법입니다. whyAmI의 선언을 포함해야한다 문을 사용하는 기타가 사용-ified하게 할 필요가 단지 서비스 인스턴스의 주장하면서 우리의올바른 사용 범위

public Guid IsServerReachable() 
{ 
    try 
    { 
    WhoAmIResponse whoAmI; 
    using (OrganizationServiceProxy service = GetService()) 
     whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; 
    return whoAmI.UserId; 
    } 
    catch { return Guid.Empty; } 
} 

하나는 주장한다. 나는 내 이론이 무엇인지 말하고있는 것이 아니라 분명히 틀렸다. 어느?

+0

OrganizationService는 처리됩니다 (ID가 할당 된 경우). 그러나 WhoAmI가 OrganizationService를 참조합니다. 따라서 처분 된 이후에 반환 된 물건을 얻지 못할 것입니다! using 문 내에서 반환이 필요할 것입니다. – Dave

+2

변수 whoAmI의 전체 범위가 using 블록 (누락 된 괄호가 여기에 약간 혼란 스럽습니다) 인 경우,'return whoAmI'가 실행될 때 exim은조차되지 않습니다. –

+0

모든 세 줄 (선언, 할당 및 반환)을 포함하면 여기에 어떤 문제가 있는지 알지 못합니다. –

답변

0
using (OrganizationServiceProxy service = GetService()) 
    whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; 

이 해당됩니다 의심의 경우

, 시도 - finally 블록으로 사용하여 블록을 재 작성 일반적으로 유용 . 나는이를 작성하는 경향이 whoAmI은 폐기 여부에 영향을 미치지 않습니다

public Guid IsServerReachable() 
{ 
    try 
    { 
     using (OrganizationServiceProxy service = GetService()) 
     { 
      WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; 
      return whoAmI.UserId; 
     } 
    } 
    catch { return Guid.Empty; } 
} 

- 유일한 것은 자동으로 service은 폐기하기. WhoAmIResponse는 또한 IDisposable했다

경우에는 자동으로 모두를 해제하려면 다음을 작성해야 할 것 : 그것은 실제처럼 작은 어떤 using 문장의 범위에 대한 가장 좋은 방법은

using (OrganizationServiceProxy service = GetService()) 
    using (WhoAmIResponse whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse) 
     return whoAmI.UserId; 
+1

아닙니다. 나는'GetService()'할당이'try' 내에서 발생한다는 것을 확신합니다. 그래서 스레드가 try = finally 블록에 들어가기 전에 예외가 있다면 여전히 처리됩니다. 편집 : 참조 http://stackoverflow.com/a/2732078/1269654 –

+0

네, 올바른 방법은'try-catch' 블록에 이것을 쓰는 것입니다 .. –

+1

* 서비스 *의 선언도 안에 * 시도해서는 안됩니다 *? –

1

문은 문이 종료 될 때 처리해야하는 개체의 선언을 포함해야합니다. OrganizationServiceProxyIDisposableWhoAmIResponse을 구현하는 경우 코드가 정확합니다.

OrganizationServiceProxy service = GetService(); 
try 
{ 
    whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; 
} 
finally 
{ 
    if (myRes!= null) 
     // Call the object's Dispose method. 
     ((IDisposable)service).Dispose(); 
} 
+1

이것은 'try/finally'블록을 작성하는 올바른 방법이 아닙니다. 만약에 예외가 스레드에 던져지기 전에 try 블록에 들어가면 절대로 서비스를 폐기하지 않을 것입니다. See : http://stackoverflow.com/a/2732078/1269654 –

+0

실제로'WhoAmIResponse'가'IDisposable'을 구현하는지 여부는 정확하지 않습니다. –

5

모두가 올바른 :에

OrganizationServiceProxy service = GetService(); 
try { 
    whoAmI = service.Execute(new WhoAmIRequest()) as WhoAmIResponse; 
} finally { 
    service.Dispose(); 
} 
+0

이것은 유일한 정답 인 IMO입니다. –

+0

* whoAmI *를 * using *의 범위 밖에서 선언 한 메서드를 사용하는 매우 강력한 이유가 있습니다. 감사. –

+1

관심이 있으신 분 : 이유는 무엇입니까? 필자가 쓰고있는 것에 대해 매우 강한 이유가있다 .-D –

1

. OrganizationServiceProxy에 의해 반환 된 객체가 Dispose 메서드를 실행할 때 처리되지 않는 한 표시된 범위는 완벽하게 수용 할 수 있습니다.

2

whoAmI의 선언은 실제로이 경우 성능/범위 측면에서 아무런 차이를 만들지 않기 때문에. 정말 내려 오는 것은 whoAmI.UserId의 부동산 액세스도 using에 포함되어야합니다. IL 관점에서 보면 기능이 인 경우 OrganizationalServiceProxy.Dispose 메서드가 호출되는 순서와 WhoAmIResponse.UserId에 액세스하는 순서가 다릅니다.

(편집 : 나는 try/catch는 기본 값을 반환 처리하는 방법과 실제 문제가 있다고 생각하지 않으며, 그 질문의 일부가 될 것 같지 않기 때문에,이 또한 생략)

날기 내에서 모든 것을 선언하는 반면

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   

:의 IL에

public Guid IsServerReachableOutsideUsingScope() 
{ 
    WhoAmIResponse whoAmI; 
    using(var service = new Service()) 
     whoAmI = service.Execute(); 
    return whoAmI.UserId; 
} 

결과 : 게시 된 코드에서

는합니다 (IL 명확를 만들기 위해 간체) g 블록 :

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 속성을 사용하여 부작용을 액세스하고 실행 한 경우 다음에을 실행하면 예외가 throw됩니다 (Dispose).

이 상당히 드문 경우입니다 (EDIT이 : 그리고 얻을 액세스 부작용과 예외를 던지는 Dispose() 모두 나쁜 관행을 고려 주목해야한다)는, 그것이 경우가 여기에있다 경우 그때 당신이해야한다, 제안 이들이 정확함을 고려하십시오. 이것들이 문제가 아닌 경우 (부작용이없고 접근/처분 순서에 신경 쓰지 않는다면), 장기간에 걸쳐 당신과 당신 팀이 유지 보수가 가능하거나 읽을 수있는 것을 사용하십시오.