C# 10 - is there a way to make "var" define the variable as non-nullable?
Asked Answered
C

2

8

When I write this statement:

var x = new ClassName();

x is implicitly typed as a ClassName?. That is, since ClassName is a reference type, implicit assignments using var automatically define as nullable (even when I am providing a non-null instance and never modifying it).

My question is, is there any way to make non-nullability the default when using the "var" keyword?

I'm aware of this question and associated info: Why does Visual Studio Type a Newly Minted Array as Nullable?

Collotype answered 10/1, 2023 at 22:23 Comment(6)
All classes implicitly nullable.Jackstay
According to the documentation, it isn't possible. It says "However, any implicitly typed local variables (declared using var) are nullable reference types." That would seem to be in direct conflict with the normal var type inference, but that how the language was designed, which was t make using var with nullable reference types easier.Guernsey
Note that in recent versions of C# (since 9) new handles target typing, so you could do ClassName x = new();Guernsey
Or you can disable nullable types in your whole project by changing <Nullable>enable</Nullable> to <Nullable>disable</Nullable>. You can also change nullability in your code by placing #nullable disable ... #nullable enable around your properties.Chapel
'var' isn't the problem. If you use var with a non-nullable type (like dateTime) you'll find you get compile errors doing (var foo = DateTime.Now;foo=null;). The issue is that classes are nullable by default. What is your use case for this feature? there might be workarounds like a NonNullable<T> class or somethingGunpowder
@TheLemon - really what I'm looking for is an equivalent to JS/TS const x = or F#'s let x = - a semantic way to declare that this identifier is permanently bound to the initially set value (and thus, if the initial value is not null, the identifier never will be either). (I realize that var is still going to allow the value to vary, but I want to at least establish that it should never be set to null.)Collotype
C
8

is there any way to make non-nullability the default when using the "var" keyword

No, as it is stated in the docs - var always implies nullable reference type:

When var is used with nullable reference types enabled, it always implies a nullable reference type even if the expression type isn't nullable. The compiler's null state analysis protects against dereferencing a potential null value. If the variable is never assigned to an expression that maybe null, the compiler won't emit any warnings. If you assign the variable to an expression that might be null, you must test that it isn't null before dereferencing it to avoid any warnings.

But null state analysis can determine if variable is not actually null and do not emit warnings in quite a lot of cases (hence the part with emphasis in the quote):

public class C 
{
    public string M(string? j) {
        var foo = "";
        var bar = j;
        // return foo; // no warning
        return bar; // warning
    }
}

Demo

If for some reason you still need explicitly non-nullable type you can work around with target typed new expressions in some cases:

MyClass x = new();

Also you can consider disabling nullable reference types (locally of for the whole project) or using null-forgiving operator (!).

Cloudlet answered 11/1, 2023 at 7:54 Comment(1)
MyClass x = new() seems to be the most concise way to define the variable as non-nullable.Collotype
G
0

(answering the use case in your comment more so than the question). If you want a readonly non-nullable decorator (presumably at the method level scope, otherwise you could just use the 'readonly' declaration), you could create a generic class with the functionality you're after. It's not quite an alternative to 'var' - but it would cater to your use case to some degree.

public class ReadOnly<T>
{
    private T _value;
    public T value { get { return _value; } }
    public ReadOnly(T initialValue)
    {
        if (initialValue == null)
            throw new ArgumentException("value must be non-null");
        _value = initialValue;
    }
    public static implicit operator T(ReadOnly<T> readOnly)
    {
        return readOnly.value;
    }
}
public class Foo {
    public void Bar() {
        var myReadonlyFoo = new ReadOnly<Foo>(this);
        myReadonlyFoo.value = this;//compile error
        var tempVar = myReadonlyFoo.value;//this works fine
        myReadonlyFoo.value.Bar();//this works fine, but will crash the app lol

        Foo test = myReadonlyFoo; //with some implicit conversion for the fun of it

    }
}
Gunpowder answered 13/1, 2023 at 2:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.