Home > Back-end >  How to implicitly convert nullable type to non-nullable type
How to implicitly convert nullable type to non-nullable type

Time:12-21

I have a nullable c# 10 .net 6 project with an extension method to ThrowIfNull

using System;
using System.Runtime.CompilerServices;

#nullable enable
public static class NullExtensions
{
    public static T ThrowIfNull<T>(
        this T? argument, 
        string? message = default, 
        [CallerArgumentExpression("argument")] string? paramName = default
    )
    {
        if (argument is null)
        {
            throw new ArgumentNullException(paramName, message);
        }
        else
        {
            return argument;
        }
    }
}

The extension method implicitly converts string? to string but it does not work for other primitive types like int? or bool?

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        string? foo = "foo";
        string nonNullableFoo = foo.ThrowIfNull();  // success from "string?" to "string"
        Console.WriteLine(nonNullableFoo);
        
        bool? baz = true;
        bool nonNullableBaz = baz.ThrowIfNull();    // success from "string?" to "string"
        Console.WriteLine(nonNullableFoo);
        
        int? bar = 2;
        int nonNullableBar = bar.ThrowIfNull(); // error: Cannot implicitly convert type 'int?' to 'int'
        Console.WriteLine(nonNullableBar);
    }
}

How do I make the extension implicitly convert int? and bool??

Here is the full dotnet fiddle https://dotnetfiddle.net/LiQ8NL

CodePudding user response:

Found one possible option in MS dotnet docs https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

Constraint "where T : struct" The type argument must be a non-nullable value type

Also according to this answer https://stackoverflow.com/a/8745492/2877168 it is not possible to make this work for string? and all other value types. So only way is to define two extension methods. Here is the updated version that works for string? and int?, bool? etc

public static class NullExtensions
{
    public static T ThrowIfNull<T>(this T? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
        where T : struct
    {
        if (argument is null)
            throw new ArgumentNullException(paramName, message);
        return (T)argument;
    }

    public static string ThrowIfNull(this string? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
    {
        if (argument is null)
            throw new ArgumentNullException(paramName, message);
        return argument;
    }
}

A working version of this is at https://dotnetfiddle.net/uBX1w6

CodePudding user response:

You can achieve your goal by providing one extension method for non-nullable reference types and another for unmanaged (e.g. int, bool, ...) types. Note that unmanaged types require a cast.

public static class NullExtensions
{
    public static T ThrowIfNull<T>(
        this T? argument,
        string? message = default,
        [CallerArgumentExpression("argument")] string? paramName = default
    ) where T : notnull
    {
        if (argument is null)
        {
            throw new ArgumentNullException(paramName, message);
        }
        else
        {
            return argument;
        }
    }

    public static T ThrowIfNull<T>(
        this T? argument,
        string? message = default,
        [CallerArgumentExpression("argument")] string? paramName = default
    ) where T : unmanaged
    {
        if (argument is null)
        {
            throw new ArgumentNullException(paramName, message);
        }
        else
        {
            return (T)argument;
        }
    }
}

Use like this:

int? foo = 42;
int bar = foo.ThrowIfNull();
Console.WriteLine(bar);

string? baz = "Hello";
string quus = baz.ThrowIfNull();
Console.WriteLine(quus);

// Comment out either this
baz = null;
quus = baz.ThrowIfNull();
// Or this
foo = null;
bar = foo.ThrowIfNull();

CodePudding user response:

1. ?? Using the Operator

To assign a nullable value to a non-null variable, consider the following code:

int? value = 28;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
  • Output: The result is 28
int? value = null;
int result = value ?? -1;
Console.WriteLine($"The result is {result}");
  • Output: The result is -1

2. Editing The Code

Rearrange the code as follows. The conditional logical operators && and || don't support bool? operands. Therefore bool? You can use the type implicitly:

int? bar = 2;
int nonNullableBar = bar ?? -1; 
Console.WriteLine(nonNullableBar);
bool? baz = true;
bool nonNullableBaz = false;
        
if (baz == true){ 
    nonNullableBaz = true;
} 
else if(baz == false){ 
    nonNullableBaz = false;
} 
else {
    /* Something */
}

3. Resources

  • Related