1

I usually check nullable types with if (foo is not null), and afterwards I can use foo like the non-null type. Why doesn't this work with structs? Even the ! operator does not help. Is this a bug or am I missing something? What's the shortest workaround?

Foo? foo = new Foo { a = "foo" }; 
if (foo is not null) {
    Console.WriteLine(foo.a);  // Works, prints "foo"
}

Bar? bar = new Bar { a = "bar" };
if (bar is not null) {
    Console.WriteLine(bar.a);  // Error: Bar? does not contain a definition for "a"
    Console.WriteLine(bar!.a); // Same error
}

class Foo {
    public string a;
}
struct Bar {
    public string a;
}
3
  • 3
    Because a nullable struct is of type Nullable<T> which is completely different from a nullable reference type. You have to use .Value to access the value of a nullable struct. Commented Jun 29, 2022 at 8:32
  • 1
    What works in both cases is pattern matching: if (foo is Foo notNullFoo) Console.WriteLine(notNullFoo.a). Commented Jun 29, 2022 at 8:34
  • 1
    And if repeating the type name seems undesirable, {} can be used instead: if (bar is {} notNullBar) Console.WriteLine(notNullBar.a). Eliminating notNullBar can only be done at the cost of exposing the structural differences between nullable reference types and nullable value types. Commented Jun 29, 2022 at 8:43

3 Answers 3

4

Backwards-compatibility.

Nullable value types exist since C# 2.0, and they are implemented differently than nullable reference types (since C# 8.0).

  • int? is a synonym for Nullable<int>, which is a completely different type than int. There is some compiler magic (lifted operators) to make it behave similarly, but Nullable<int> has members that int doesn't have (HasValue, Value) and vice-versa (ToString(string)).
  • string? on the other hand, is of type string, with additional compile-time checks enabled.

Making a null-check on int? allow you to access the underlying int without "unwrapping" it with .Value would have broken tons of existing code.


You can, however, use pattern matching to create a new variable with the underlying type:

int? a = 3;      // implicit conversion from int to Nullable<int>

if (a is int b)
{
    // Use b to access the underlying int here.
}
else
{
    // a was null
}
Sign up to request clarification or add additional context in comments.

Comments

2

Structs are value types and cannot be assigned to null. By declaring the struct as nullable you wrap them in a Nullable<T> struct. You should check the HasValue and Value property of the Nullable<Bar> struct in you case.

        Bar? bar = new Bar { a = "bar" };
        if (bar.HasValue)
        {
            Console.WriteLine(bar.Value.a);
            Console.WriteLine(bar.Value.a);
        }

Comments

1

A struct is a value type so it's never null. You can check the default value for struct

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.