Home > Enterprise >  Condition program flow on whether a `double?` is null
Condition program flow on whether a `double?` is null

Time:01-11

In C#, you can append a question mark to a type to indicate that it may hold either a value of a type or return null:

double? MySqrt(double a)
{
    return (a > 0.0) ? Math.Sqrt(a) : null;
}

Console.WriteLine(MySqrt(4.5));     // 2.1213203435596424
Console.WriteLine(MySqrt(-4.5));    // a blank line

Now, if I want to condition a variable assignment the result of this function, I can use the ?? operator, e.g.

double b = MySqrt(-2.0) ?? 0.0;
Console.WriteLine(b);     // 0

But without redefining MySqrt, how can I control the larger programmatic flow (not just a single variable assignment) based on whether or not MySqrt returned null?

The following, for example, yields a compiler error:

void DrawSquareWithArea(double area)
{
    double sideLength = MySqrt(area);
    if (sideLength != null)
    {
        // Draw a square on the screen
        DrawSquare(sideLength);
    }
    else
    {
        // Display some visual feedback indicating that input was invalid
        DisplayErrorFeedback();
    }
}
// error CS0266: Cannot implicitly convert type 'double?' to 'double'. An explicit conversion exists (are you missing a cast?)

Note that the function DrawSquare() requires a double argument here, so changing sideLength to a double? is another compiler error.

CodePudding user response:

By using the correct type (Nullable<double> a.k.a. double?). The non-null value can be accessed by means of the Value property (which has type double here):

void DrawSquareWithArea(double area)
{
    double? sideLength = MySqrt(area);
    if (sideLength != null) // or: if (sideLength.HasValue)
    {
        // Draw a square on the screen
        DrawSquare(sideLength.Value);
    }
    else
    {
        // Display some visual feedback indicating that input was invalid
        DisplayErrorFeedback();
    }
}

Or have the compiler infer the type:

var sideLength = MySqrt(area);

CodePudding user response:

You can't convert explicitly double? to double. Either check for null and use .Value:

void DrawSquareWithArea(double area)
{
    double? sideLength = MySqrt(area);
    if (sideLength is not null)
    {
        // Draw a square on the screen
        DrawSquare(sideLength.Value); // sideLength.Value is double
    }
    //...
}

or use pattern matching with declaration pattern:

void DrawSquareWithArea(double area)
{
    if (MySqrt(area) is {} len) // checks for null and assigns variable of double type
    {
        // Draw a square on the screen
        DrawSquare(len);
    }
    //...
}

or :

void DrawSquareWithArea(double area)
{
    if (MySqrt(area) is double len) // checks for null and assigns variable of double type
    {
        // Draw a square on the screen
        DrawSquare(len);
    }
    //...
}

Read more:

CodePudding user response:

The other answers are perfectly fine. However I would like to add another approach which could be quite handy and (from my perspective) might be even better than using null as return type. If your method is called with a non valid value why not simply throw an exception? In your calling method, handle the thrown exception. A minimal working example could look like the following.

class Program
{
    static void Main(string[] args)
    {
        try{
            MySqrt(-5);
        } catch(Exception e) {
            Console.WriteLine(e.Message);
        }
    }
    static double MySqrt(double a)
    {
        if(a > 0.0) return Math.Sqrt(a);
        throw new ArithmeticException("Can not calculate square root of negative value!");
    }
}
  •  Tags:  
  • c#
  • Related