Skip to content

Commit

Permalink
mark all structs as readonly; fix some compiler noise (no functiona…
Browse files Browse the repository at this point in the history
…l change) (#1925)
  • Loading branch information
mgravell committed Jun 20, 2023
1 parent d91d904 commit 20d8138
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Dapper/CommandDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Dapper
/// <summary>
/// Represents the key aspects of a sql operation
/// </summary>
public struct CommandDefinition
public readonly struct CommandDefinition
{
internal static CommandDefinition ForCallback(object parameters)
{
Expand Down
20 changes: 19 additions & 1 deletion Dapper/SqlMapper.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ public static Task<int> ExecuteAsync(this IDbConnection cnn, CommandDefinition c
}
}

private struct AsyncExecState
private readonly struct AsyncExecState
{
public readonly DbCommand Command;
public readonly Task<int> Task;
Expand Down Expand Up @@ -1220,6 +1220,24 @@ private static async Task<T> ExecuteScalarImplAsync<T>(IDbConnection cnn, Comman
}

#if NET5_0_OR_GREATER
/// <summary>
/// Execute a query asynchronously using <see cref="IAsyncEnumerable{dynamic}"/>.
/// </summary>
/// <param name="cnn">The connection to query on.</param>
/// <param name="sql">The SQL to execute for the query.</param>
/// <param name="param">The parameters to pass, if any.</param>
/// <param name="transaction">The transaction to use, if any.</param>
/// <param name="commandTimeout">The command timeout (in seconds).</param>
/// <param name="commandType">The type of command to execute.</param>
/// <returns>
/// A sequence of data of dynamic data
/// </returns>
public static IAsyncEnumerable<dynamic> QueryUnbufferedAsync(this DbConnection cnn, string sql, object param = null, DbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)
{
// note: in many cases of adding a new async method I might add a CancellationToken - however, cancellation is expressed via WithCancellation on iterators
return QueryUnbufferedAsync<dynamic>(cnn, typeof(object), new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.None, default));
}

/// <summary>
/// Execute a query asynchronously using <see cref="IAsyncEnumerable{T}"/>.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Dapper/SqlMapper.DeserializerState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Dapper
{
public static partial class SqlMapper
{
private struct DeserializerState
private readonly struct DeserializerState
{
public readonly int Hash;
public readonly Func<DbDataReader, object> Func;
Expand Down
2 changes: 1 addition & 1 deletion Dapper/SqlMapper.LiteralToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public static partial class SqlMapper
/// <summary>
/// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql
/// </summary>
internal struct LiteralToken
internal readonly struct LiteralToken
{
/// <summary>
/// The text in the original command that should be replaced
Expand Down
9 changes: 4 additions & 5 deletions Dapper/SqlMapper.TypeDeserializerCache.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Text;

namespace Dapper
{
Expand All @@ -16,7 +15,7 @@ private TypeDeserializerCache(Type type)
this.type = type;
}

private static readonly Hashtable byType = new Hashtable();
private static readonly Hashtable byType = new();
private readonly Type type;
internal static void Purge(Type type)
{
Expand Down Expand Up @@ -51,9 +50,9 @@ internal static void Purge()
return found.GetReader(reader, startBound, length, returnNullIfFirstMissing);
}

private readonly Dictionary<DeserializerKey, Func<DbDataReader, object>> readers = new Dictionary<DeserializerKey, Func<DbDataReader, object>>();
private readonly Dictionary<DeserializerKey, Func<DbDataReader, object>> readers = new();

private struct DeserializerKey : IEquatable<DeserializerKey>
private readonly struct DeserializerKey : IEquatable<DeserializerKey>
{
private readonly int startBound, length;
private readonly bool returnNullIfFirstMissing;
Expand Down
4 changes: 3 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ Note: to get the latest pre-release build, add ` -Pre` to the end of the command

### unreleased

- reinstate fallback support for `IDataReader`, and implement missing `DbDataReader` async APIs
- add missing non-generic `AsyncEnumerable<dynamic> QueryUnbufferedAsync(...)` API (#1925 via mgravell, fixes #1922)
- formally mark all `struct` types as `readonly` (#1925 via mgravell)
- reinstate fallback support for `IDataReader`, and implement missing `DbDataReader` async APIs (#1913 via mgravell)

(note: new PRs will not be merged until they add release note wording here)

Expand Down
16 changes: 15 additions & 1 deletion tests/Dapper.Tests/AsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ public async Task TestBasicStringUsageAsync()
}

#if NET5_0_OR_GREATER
[Fact]
public async Task TestBasicStringUsageUnbufferedDynamicAsync()
{
var results = new List<string>();
await foreach (var row in connection.QueryUnbufferedAsync("select 'abc' as [Value] union all select @txt", new { txt = "def" })
.ConfigureAwait(false))
{
string value = row.Value;
results.Add(value);
}
var arr = results.ToArray();
Assert.Equal(new[] { "abc", "def" }, arr);
}

[Fact]
public async Task TestBasicStringUsageUnbufferedAsync()
{
Expand Down Expand Up @@ -192,7 +206,7 @@ public async Task TestBasicStringUsageAsyncNonBuffered()
[Fact]
public void TestLongOperationWithCancellation()
{
CancellationTokenSource cancel = new CancellationTokenSource(TimeSpan.FromSeconds(5));
CancellationTokenSource cancel = new(TimeSpan.FromSeconds(5));
var task = connection.QueryAsync<int>(new CommandDefinition("waitfor delay '00:00:10';select 1", cancellationToken: cancel.Token));
try
{
Expand Down

0 comments on commit 20d8138

Please sign in to comment.