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!");
}
}