C
C#2y ago
.logik.

✅ Help with non-nullable field must contain a non-null value when exiting constructor.

Following an online tutorial and trying to resolve nullable reference warnings (the tutorial was before nullable reference types were introduced). I have a GameSession class with the constructor defined as
public GameSession()
{
CurrentPlayer = new Player
{
Name = "MyName",
Gold = 1000000,
CharacterClass = "Ranger",
HitPoints = 10,
ExperiencePoints = 0,
Level = 1,
};

CurrentWorld = WorldFactory.CreateWorld();

CurrentLocation = CurrentWorld.LocationAt(0, -1);
}
public GameSession()
{
CurrentPlayer = new Player
{
Name = "MyName",
Gold = 1000000,
CharacterClass = "Ranger",
HitPoints = 10,
ExperiencePoints = 0,
Level = 1,
};

CurrentWorld = WorldFactory.CreateWorld();

CurrentLocation = CurrentWorld.LocationAt(0, -1);
}
The error is regarding the backing field private Location _currentLocation which is set using the property
public Location CurrentLocation
{
get => _currentLocation;
set
{
_currentLocation = value;
OnPropertyChanged();
}
}
public Location CurrentLocation
{
get => _currentLocation;
set
{
_currentLocation = value;
OnPropertyChanged();
}
}
Furthermore the LocationAt method is non-nullable defined as
public Location LocationAt(int xCoordinate, int yCoordinate)
{
foreach (Location loc in _locations)
{
if (loc.XCoordinate == xCoordinate && loc.YCoordinate == yCoordinate)
{
return loc;
}
}

throw new LocationNotFoundException($"Location at x:{xCoordinate} y:{yCoordinate} does not exist");
}
public Location LocationAt(int xCoordinate, int yCoordinate)
{
foreach (Location loc in _locations)
{
if (loc.XCoordinate == xCoordinate && loc.YCoordinate == yCoordinate)
{
return loc;
}
}

throw new LocationNotFoundException($"Location at x:{xCoordinate} y:{yCoordinate} does not exist");
}
So my question is, why am I still getting the warning and what is the best approach to fixing it? As I understand it, the compiler already knows that LocationAt will return a Location and the backing field _currentLocation should be set by the CurrentLocation property in the constructor. Why does it still think currentLocation is null when exiting constructor? TIA
6 Replies
333fred
333fred2y ago
The compiler doesn't do cross-method analysis, so it has no idea that CurrentLocation will set _currentLocation If you want to inform it of that, put [MemberNotNull(nameof(currentLocation))] on your setter. Though, are you sure you want to invoke OnPropertyChanged in your constructor? That's often incorrect
.logik.
.logik.OP2y ago
Ahh that makes sense, yeah looking back at it now, I should probably be setting the field directly so to confirm - if i wanted to use that attribute, it would look like the below? or does the attribute need to go before the property?
public Location CurrentLocation
{
get => _currentLocation;
[MemberNotNull(nameof(_currentLocation))]
set
{
_currentLocation = value;
OnPropertyChanged();
}
}
public Location CurrentLocation
{
get => _currentLocation;
[MemberNotNull(nameof(_currentLocation))]
set
{
_currentLocation = value;
OnPropertyChanged();
}
}
333fred
333fred2y ago
Like you have it there Putting it on the whole attribute would mean that calling either getter or setter would ensure the member is not null And that's not correct: the getter doesn't modify the field
.logik.
.logik.OP2y ago
Great - thanks for that. I'm probably not going to use it because I agree that I should be setting the field directly. I'll do some digging to see when/if its ever appropriate to be using the property to set backing fields in a constructor. Appreciate your assistance!
333fred
333fred2y ago
yw Don't forget to $close if there's no more questions 🙂
MODiX
MODiX2y ago
Use the /close command to mark a forum thread as answered
Want results from more Discord servers?
Add your server