Reputation: 270733
Consider this code snippet, which has no nullable warnings.
public class Foo {
public string Property { get; } = "Some String";
}
public class Bar {
[DisallowNull]
public Foo? Foo { get; private set; }
[MemberNotNull(nameof(Foo))]
public void MyMethod() {
Foo = new Foo();
// After setting Foo, I use Foo.Property in some way
Console.WriteLine(Foo.Property);
}
}
Since in my real code, I use Foo.Property
after setting Foo
a lot, I wanted to add a "convenient property" to Bar
that returns it directly, so that I can access it with a shorter name (Foo
is actually a rather long name in my real code):
// in Bar
public string? Property => Foo?.Property;
// ...
// Now I can do:
Console.WriteLine(Property);
However, now Bar.Property
is nullable, even in a place where Foo
is definitely not null (such as just after setting Foo
). So when I use Property
in a place where null is not allowed, the compiler gives me warnings.
I thought what I needed is to annotate Property
with something like NotNullIfMemberNotNull(nameof(Foo))
, but after looking it up, this attribute is only proposed, and doesn't exist yet.
How can I work around this?
Upvotes: 4
Views: 422
Reputation: 310792
Firstly, MemberNotNull
is a post condition that only signals to callers that the specified member will not be null after the member returns. It will not help you within the method itself unfortunately.
I understand you're using a simplification of a larger pattern, but one way I would suggest rewriting MyMethod
is:
public void MyMethod() {
var foo = new Foo();
Foo = foo;
Console.WriteLine(foo.Property);
}
Upvotes: 1
Reputation: 270733
One workaround I came up with is make both Foo
and Property
have backing fields. In the setter of Foo
, also set Property
. This way, we can add the MemberNotNull
attribute to the setter of Foo
.
private Foo? foo;
[DisallowNull]
public Foo? Foo {
get => foo;
[MemberNotNull(nameof(Property))]
private set {
foo = value;
Property = value.Property;
}
}
public string? Property { get; private set; }
However, this isn't very general. It only works because Foo
just happens to be marked as DisallowNull
.
Upvotes: 2