Clause `using` de Dapper - Clarification?

c# dapper

Question

J'apprends comment Dapper travaille dans les coulisses.

Cependant, j'ai vu ce modèle de disposition qui ne m'a pas été compris.

À peu près général € » c'est de savoir comment QueryAsync est mis en œuvre:

/*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*/   }

Je peux comprendre pourquoi il n'a pas utilisé l' using via la connexion, c'est parce qu'il voulait fermer conditionnellement la connexion via la variable wasClosed .
Pour ce faire, il doit utiliser la clause try/finally . (donc la fermeture conditionnelle sera dans la clause finally )

Mais ma question concerne la ligne 32.

Au lieu de recourir à la dernière clause , il pourrait faire:

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;
}

Donc, la clause finally est laissée avec:

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

Question

J'ai vu cette clause using dans une clause finally plusieurs fois dans dapper.

Il faut que je manque quelque chose ici, mais qu'est-ce que ce modèle réalise que ma suggestion ne fait pas?

Réponse acceptée

Je ne suis pas @MarcGravell, mais je pense qu'il y a une chose qui vous manque. Le code que vous avez collé ne correspond pas exactement au lien que vous avez référencé. Le chemin de code correspondant ressemble à ceci:

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();
}

La méthode peut soit renvoyer un résultat mis en mémoire tampon (indiqué par le drapeau command.Buffered ) ou un itérateur différé. Si Marc devait envelopper le lecteur avec une instruction using et renvoyer un itérateur, celui-ci (le lecteur) serait éliminé au moment où le site d'appel l'exécuterait. En définissant le lecteur sur null (dans la ligne avant de renvoyer le résultat différé), il empêche le lecteur d’être éliminé, car l’utilisation dans le bloc pourraient être converties en ceci:

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

Quand il met le lecteur à null , il n'est pas éliminé et la référence existante dans l'itérateur est toujours active, pointant vers le lecteur. De cette façon, il peut à la fois disposer le lecteur dans le chemin de code normal, mais le garder en vie si un itérateur différé était demandé.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi