I use null
to denote that an optional parameter A? a
of a function should assume a non-null default value, computed in the function. After entering the function, I check whether the passed-in argument a
is null
, and if so, assign a
a non-null value. From that point on, it can safely be assumed that a
is non-null. The problem: the compiler is not aware of this, and now I have to refer to a.Value
for the rest of the function, instead of the straightforward a
.
Is there a way to tell the compiler that a
is actually non-null from some point on? If not, what is the clearest way to deal with such optional parameters?
Example code:
using System;
namespace test
{
public struct A { public int x; };
class Program
{
static void f(A? a = null)
{
// Assign the default value.
if (a == null) a = new A { x = 3 };
// Now 'a' is non-null for the rest of the function.
// What I do now:
Console.WriteLine(a.Value.x);
// What I'd like to do:
// * Mark 'a' as non-null somehow.
// Now can refer to 'a' directly:
// Console.WriteLine(a.x);
}
static void Main(string[] args)
{
f();
}
}
}
CodePudding user response:
It looks like you just want to allow the method to be called without specifying a parameter (and use a certain default in that case).
There is another possible solution to this particular scenario:. Just overload f()
like so:
static void f()
{
f(new A { x = 3 });
}
static void f(A a)
{
Console.WriteLine(a.x);
}
Code can then call f()
with or without a parameter, but the difference is that in the case where it calls f(A a)
with a parameter, it cannot be null.
(In response to your comment below.)
If you want to handle being able to call with a possibly-null struct, you can overload like this instead:
static void f(A? a = default)
{
f(a ?? new A { x = 3 });
}
static void f(A a)
{
Console.WriteLine(a.x);
}
That means your implementation doesn't have to deal with a possibly-null value, but you can still omit the argument at the call site, or call it with a null value.
Note: You can simplify static void f(A? a = default)
to:
static void f(A? a = default) => f(a ?? new A { x = 3 });
if you prefer the shorter syntax.
CodePudding user response:
No, there isn't - not for a nullable value type. The compile-time type of a nullable value type is still Nullable<T>
, even if the compiler knows that it will be non-null.
This is different from nullable reference types where the compiler keeps track of whether it thinks the variable may be null in order to warn about dereferencing. With nullable reference types, there are no "real" separate nullable and non-nullable types - just the single reference type with an indication of whether the value might be null.
The approach of introducing a new non-nullable variable as given in comments on the question is really the only way forward here.
CodePudding user response:
No, it cannot be done. A?
is a shortcut for Nullable<A>
. Nullable<A>
is clearly a different type to A
, and in order to get the value, you need to use Nullable<A>.Value
.
The best option you have is, as was commented by @MatthewWatson, to introduce another variable:
A aValue = a ?? new A { x = 3 };
Something that can help is to properly name the parameter and the actual value being used, to help differentiate them:
static void f(A? optionalA = null)
{
// Use optionalA if it has a value, or the default value otherwise.
var a = optionalA ?? new A { x = 3 };
CodePudding user response:
You should be able to use properties for this.
With properties, you can assign fields to new values, and make sure these properties either return the expected value, or a default value.
Like this:
int? a = null;
public int a2
{
get
{
return a.GetValueOrDefault(3);
}
}
Then you can use property a2
instead of a
Not exactly the same as changing a field from nullable to non-nullable, but it may do the thing that you expected to do.