1

How to avoid this Warning

warning CS8602: Dereference of a possibly null reference

The code:

public async Task<IEnumerable<T>> ExecuteQuery<T>(string commandText, string ctx, CancellationToken cancellationToken, CommandType commandType = CommandType.Text, object? paramSet = null)
{
    var dtsrc = CheckConnectionToDbServer(ctx, cancellationToken);
    //if (dtsrc == null) { _logger.LogTrace($"{methodName}: No datasource!"); return 0; }
    var con = dtsrc.OpenConnection();//<---? 
    IEnumerable<T> result2 = await con.QueryAsync<T>(commandText, paramSet, commandType: commandType).ConfigureAwait(false);
    return result2;
}

-- If dtsrc is null then con is null too and I cannot return Task<IEnumerable<T>> from the function. How to fix it?

And the 2nd function: how to return null or something like in case of no connection?

public async Task<T> ExecuteScalarQuery<T>(string commandText, string ctx, CancellationToken cancellationToken, CommandType commandType = CommandType.Text, object? paramSet = null)
{
    string methodName = nameof(ExecuteScalarQuery);
    _logger.LogTrace($"{methodName}: {ctx}");
    var dtsrc = CheckConnectionToDbServer(ctx, cancellationToken);

    if (dtsrc == null)
    {
        _logger.LogTrace($"{methodName}: No datasource!");
        //return // -<---???
    }
    var con = dtsrc.OpenConnection();
    return await con.QuerySingleAsync<T>(commandText, paramSet, commandType: commandType).ConfigureAwait(false);
}
ZedZip
  • 5,794
  • 15
  • 66
  • 119
  • Does this answer your question? [In C# 8, why does type inference on new expressions result in nullable references?](https://stackoverflow.com/questions/62685673/in-c-sharp-8-why-does-type-inference-on-new-expressions-result-in-nullable-refe) – vernou Jun 14 '23 at 10:31
  • This code is suspicious - connections are *not* meant to be cached, they should be closed as soon as possible. That's why they're always created in a `using` block. ADO.NET's connection pooling takes care of removing the cost of closing and opening connections, by resetting existing ones and reusing them. If `QueryAsync` comes from Dapper, there's no need to call `Open` either, it's done automatically. – Panagiotis Kanavos Jun 14 '23 at 10:47
  • 1
    The Dapper documentation shows how it should be used. This code should be replaced with `using(var con=new SqlConnection(conn_str){ var results=await con.QueryAsync(...); ....}`. – Panagiotis Kanavos Jun 14 '23 at 10:49
  • But what if connection is null? I need to return something from my function – ZedZip Jun 14 '23 at 10:59
  • `new SqlConnection` is never null. The far bigger problem is the multiple connection leaks that will cause this code to freeze production. Use ADO.NET and Dapper correctly and the problems go away – Panagiotis Kanavos Jun 14 '23 at 11:01
  • You wouldn't be getting a warning if `CheckConnectionToDbServer` didn't return nulls either. Which means that either it's an external method that wasn't compiled with nullability checks, or it returns `DbConnection?`, which should be happening. You can bypass this by actually checking for nulls, but *why not remove the bugs entirely* ? – Panagiotis Kanavos Jun 14 '23 at 11:03
  • Ok, how to remove this bug? – ZedZip Jun 14 '23 at 11:06
  • Please check my edited start post. I have added the 2nd function. How to re-write it? – ZedZip Jun 14 '23 at 11:10

1 Answers1

2

You are on the right path with the part you commented out. Just return an empty Enumerable.

if (dtsrc == null) 
{ 
    _logger.LogTrace($"{methodName}: No datasource!"); 
    return Task.FromResult(Enumerable.Empty<T>());
}

Alternatively you could

Throw an exception or Allow your method to return null, and check for null in your calling method and handle it there.

jason.kaisersmith
  • 8,712
  • 3
  • 29
  • 51
  • I try this: return Enumerable.Empty(); CS0117: IEnumerable does not contain a definition for Empty – ZedZip Jun 14 '23 at 10:35
  • Ah Yes, you are running async and returning a Task. I have updated it. It should work now. – jason.kaisersmith Jun 14 '23 at 10:41
  • 1
    There's no need for `Task.FromResult` as this is an `async` method. – Panagiotis Kanavos Jun 14 '23 at 10:44
  • @ZedZip [Enumerable.Empty](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.empty?view=net-7.0) is available in all .NET versions. If you get an error it's probably because you missed a `using System.Linq;` – Panagiotis Kanavos Jun 14 '23 at 10:45
  • Yes, I have added System.Linq – ZedZip Jun 14 '23 at 10:47
  • How to return null in case of : public async Task ExecuteScalarQuery(...) ? – ZedZip Jun 14 '23 at 10:49
  • @ZedZip why are you trying to wrap Dapper's methods? They work fine the way they are. They have simpler syntax than what you're trying to do, better connection management. There's `conn.ExecuteScalar(sql)` already – Panagiotis Kanavos Jun 14 '23 at 10:52
  • @PanagiotisKanavos you are right, but I mean a situation like in my 1st post: when connection is null , the query cannot be executed so I need to return something from the function – ZedZip Jun 14 '23 at 10:56
  • I need something like this if (dtsrc == null) { _logger.LogTrace($"{methodName}: No datasource!"); return Task.FromResult(Enumerable.Empty()); // <- and not Enumerable but something like Task } – ZedZip Jun 14 '23 at 10:57
  • @ZedZip the connection is never null when you create safely - in a `using` block. You're trying to cover up Dapper's safe code with custom *un*safe code – Panagiotis Kanavos Jun 14 '23 at 10:59
  • Your return type for the method is "Task>", so you can't return anything which does not confirm to this! – jason.kaisersmith Jun 14 '23 at 11:00
  • @jason.kaisersmith yes, in this function all is ok. I have the 2nd one where public async Task ExecuteScalarQuery(...) – ZedZip Jun 14 '23 at 11:01