2016-12-14 4 views
3

대기열에서 읽는 코드 블록이 하나의 항목 (자체 스레드에서)을 처리 한 다음 대기열이 비어있을 때까지 반복되는 코드 블록이 있습니다.NullReferenceException이 발생하는 이유를 이해할 수 없습니다.

public ActionResult GetOrdersAsync() { 

     int count = 0; 
     SyncDM sync = _common.StartSync(); 

     while (sync != null && sync.SyncId != 0) { 

      int customerId; 
      bool result = int.TryParse(sync.Payload, out customerId); 
      if (result) { 
       Task.Run(() => GetOrders(sync.SyncId, customerId)); 
      } 

      count++; 
      //Process the next Sync 
      sync = _common.StartSync(); 

     } 

     return Json(new JsonModel { 
      Message = "Started " + count + " instances of GetOrders", 
      Success = count > 0 
     }); 

    } 

StartSync()는 항목을 대기열에서 제거하거나 대기열이 비어 있으면 null을 반환합니다. GetOrders()는 개체를 처리합니다.

이 줄에서 코드가 NullReferenceException을 발생시키는 경우가 있습니다. Task.Run (() => GetOrders (sync.SyncId, customerId));

디버거에서 동기화는 null (예외 이유)이지만 customerId에는 값이 있습니다. 이것은 동기화가 이전 라인의 값을 가졌음을 나타냅니다. 이것은 혼란 스럽다, 나는 Task.Run과 threading과 관련이 있다고 생각하고있다. 그러나 로컬 범위 변수가 자발적으로 값을 변경하는 방법을 이해하지 못한다.

+0

동기화가 = _common.StartSync()가 (이전과 GetOrders의 동기화 개체를 무효화하는 경우가) 완료를 : 당신은 하지이 폐쇄 외부에서 수정 될 새 변수를 만드는 데 필요한 것 왜 그렇게 할 지 이해가됩니다. GetOrders 및 GetOrdersAsync()를 실제 비동기 메소드로 만들 수 있고 GetOrders를 기다릴 수 있습니까? 그런 다음 다음 동기화를 처리하기 전에 대기합니다. – Dispersia

답변

6

작업을 수행하기 전에 sync 참조를 업데이트 중입니다. 작업이 반드시 즉시 시작되는 것은 아닙니다.

sync = _common.StartSync(); 

지금 sync에 참조가 null의 경우, 그리고 귀하의 작업이 sync.SyncId 액세스로 전환 될 때, 당신은 null 참조 예외를 얻을 : 경우에 다음이 더 아래 실행 된 후, 당신의 작업을 시작할 수 있습니다.

는 다음에 코드를 변경

: 우리가 이드를 전달하려는 때문에

if (result) { 
    var syncId = sync.SyncId; 
    Task.Run(() => GetOrders(syncId, customerId)); 
} 

이 작동합니다. 객체 자체를 전달하고 싶다면 어떻게해야할까요? ,

if (result) { 
    var capturedSync = sync; 
    //Assuming GetOrders now takes a `Sync` 
    Task.Run(() => GetOrders(capturedSync, customerId)); 
} 
+1

마지막 예는 얕은 사본입니다. 동기화를 변경하면 capturedSync도 변경됩니다. 그는 깊은 사본을 작성해야합니다. 나는 첫 번째 예를 계속 유지할 것입니다. – Dispersia

+2

@Dispersia "동기화를 변경하면 capturedSync도 변경됩니다."... 그리고 그것에 대해 확실합니까? – spender

+0

@spender 예? 그것이 얕은 사본이하는 것입니다. 직접 해보고, 객체를 만들고, 할당하고 (참조로 수행합니다), 새 객체를 변경하고, 원래의 변경 사항을 확인하십시오. – Dispersia