Dapper의 중첩 된`using` 절 - 명확화?

c# dapper

문제

Dapper가 배후에서 어떻게 작동 하는지를 배우고 있습니다.

그러나 나는 나에게 이해되지 않는 처분의 이러한 패턴을 보았다.

대략 일반 â에 € " 어떻게 QueryAsync 구현됩니다

/*1*/   public async Task<IEnumerable<T>> QueryAsync<T>(string sql, Func<IDataRecord, T> projector, DbConnection _conn, dynamic param = null)
/*2*/   {
/*3*/   
/*4*/       DbDataReader reader = null;
/*5*/       bool wasClosed = _conn.State == ConnectionState.Closed;
/*6*/       try
/*7*/       {
/*8*/   
/*9*/           using (var cmd = _conn.CreateCommand())
/*10*/          {
/*11*/          if (param!=null)
/*12*/              foreach (var prop in param.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
/*13*/              {
/*14*/                  var parameter = cmd.CreateParameter();
/*15*/                  parameter.ParameterName = prop.Name;
/*16*/                  parameter.Value = prop.GetValue(param, null);
/*17*/                  cmd.Parameters.Add(parameter);
/*18*/              }
/*19*/   
/*20*/              await _conn.OpenAsync().ConfigureAwait(false);
/*21*/              cmd.CommandTimeout = 100000;
/*22*/              cmd.CommandText = sql;
/*23*/              reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false);
/*24*/              List<T> buffer = new List<T>();
/*25*/              while (await reader.ReadAsync().ConfigureAwait(false)) buffer.Add(projector(reader));
/*26*/              return buffer;
/*27*/          }
/*28*/   
/*29*/      }
/*30*/      finally
/*31*/      {
/*32*/          using (reader) { }
/*33*/          if (wasClosed) _conn.Close();
/*34*/      }
/*35*/   }

왜 그가 연결 using 통해 사용하지 않았는지 이해할 수 있습니다. 왜냐하면 wasClosed 변수를 통해 조건부로 연결을 닫으려고했기 때문입니다.
그것을하기 위해서 - 그는 try/finally 절을 사용해야합니다. (따라서 조건부 종료는 finally 절에 있습니다)

하지만 제 질문은 # 32 행에 관한 것입니다.

finally 절에서 사용 하는 대신 다음과 같이 할 수 있습니다.

using (DbDataReader reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
{
    List<T> buffer = new List<T>();
    while (await reader.ReadAsync().ConfigureAwait(false)) buffer.Add(projector(reader));
    return buffer;
}

따라서 finally 절은 다음과 같이 남습니다.

finally
{
    //using (reader) { } //removed
    if (wasClosed) _conn.Close();
}

문제

finally 절에서 여러 번이 절을 using 것을 본 적이 있습니다.

나는 여기서 뭔가를 놓치고있을 것입니다. 그러나이 패턴은 나의 제안이 얻지 못하는 것은 무엇입니까?

수락 된 답변

나는 @MarcGravell이 아니지만, 당신이 놓친 것이 하나 있다고 생각합니다. 붙여 넣은 코드가 참조하는 링크와 정확히 일치하지 않습니다. 관련 코드 경로는 다음과 같습니다.

try
{
     if (command.Buffered)
     {
         List<T> buffer = new List<T>();
         while (await reader.ReadAsync(cancel).ConfigureAwait(false))
         {
             buffer.Add((T)func(reader));
         }
         while (await reader.NextResultAsync().ConfigureAwait(false)) { }
         command.OnCompleted();
         return buffer;
     }
     else
     {
         // can't use ReadAsync / cancellation; but this will have to do
         wasClosed = false; // don't close if handing back an open reader; 
                            // rely on the command-behavior.

         var deferred = ExecuteReaderSync<T>(reader, func, command.Parameters);
         reader = null; // to prevent it being disposed before the caller gets to see it
         return deferred;
     }
}
finally
{
    using (reader) { } // dispose if non-null
    if (wasClosed) cnn.Close();
}

이 메서드는 버퍼링 된 결과 ( command.Buffered 플래그로 표시) 또는 지연된 반복기를 반환 할 수 있습니다. Marc가 using 문을 using 독자를 감싸고 반복자를 반환하면 호출자가 호출자가 실행 한 시점까지 폐기 처분을 받게됩니다. reader가 null 을 설정하면 (지연된 결과를 반환하기 전에 행에서) finally 블록에서의 사용이 다음과 같이 변환되기 때문에 판독기가 삭제되는 것을 방지합니다.

finally
{
    IDisposable disposable = reader;
    try
    {
    }
    finally
    {
        if (dispoable != null)
        {
            disposable.Dispose();
        }
    }
}

독자가 null 설정하면 판독기를 가리키며 반복기의 참조가 여전히 살아 있습니다. 이렇게하면 리더는 일반적인 코드 패스에서 독자를 처분 할 수 있지만 지연된 반복자가 요청 된 경우에는 그대로 유지합니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.