C
C#3w ago
DaClownie

NullReferenceException but checking for Null?

I click a button on my .NET MAUI UI to Create a new course. ContentPage loads, I enter my information. If I leave any of the entry fields blank, the program crashes... stating System.NullReferenceException Message=Object reference not set to an instance of an object.
private async void SaveCourseButton_Clicked(object sender, EventArgs e)
{
Course course = new Course(id, CourseName.Text, StartDate.Date, EndDate.Date, StatusPicker.SelectedIndex, InstructorName.Text, InstructorPhone.Text, InstructorEmail.Text, CourseNotes.Text, 0, 0);
var result = DataObjects.ValidateCourseInfo(activeTerm, course);
if (result.Length == 0)
{
SQLFunctions.AddNewCourse(course);
await Navigation.PopAsync();
}
else
{
await DisplayAlert("ERROR", result, "OK");
}
}

public static string ValidateCourseInfo(Term term, Course course)
{
if (course.CourseName.Length == 0 || course.CourseName is null)
{
return "Course must have a name.";
}
else if (course.EndDate.Date < course.StartDate.Date)
{
return "End date must be equal or greater than start date.";
}
else if (course.StartDate.Date < term.StartDate || course.StartDate.Date > term.EndDate || course.EndDate.Date < term.StartDate || course.EndDate.Date > term.EndDate)
{
return "Course start and end dates must fall within term start and end dates.";
}
else if (course.Status == -1)
{
return "Must pick a course status.";
}
else if (course.InstructorName.Length == 0 || course.InstructorName is null)
{
return "Instructor must have a name.";
}
...
else
{
return string.Empty;
}
}
private async void SaveCourseButton_Clicked(object sender, EventArgs e)
{
Course course = new Course(id, CourseName.Text, StartDate.Date, EndDate.Date, StatusPicker.SelectedIndex, InstructorName.Text, InstructorPhone.Text, InstructorEmail.Text, CourseNotes.Text, 0, 0);
var result = DataObjects.ValidateCourseInfo(activeTerm, course);
if (result.Length == 0)
{
SQLFunctions.AddNewCourse(course);
await Navigation.PopAsync();
}
else
{
await DisplayAlert("ERROR", result, "OK");
}
}

public static string ValidateCourseInfo(Term term, Course course)
{
if (course.CourseName.Length == 0 || course.CourseName is null)
{
return "Course must have a name.";
}
else if (course.EndDate.Date < course.StartDate.Date)
{
return "End date must be equal or greater than start date.";
}
else if (course.StartDate.Date < term.StartDate || course.StartDate.Date > term.EndDate || course.EndDate.Date < term.StartDate || course.EndDate.Date > term.EndDate)
{
return "Course start and end dates must fall within term start and end dates.";
}
else if (course.Status == -1)
{
return "Must pick a course status.";
}
else if (course.InstructorName.Length == 0 || course.InstructorName is null)
{
return "Instructor must have a name.";
}
...
else
{
return string.Empty;
}
}
9 Replies
DaClownie
DaClownie3w ago
I'm checking for a null value on the fields that could potentially be blank, and if null, passing the error message back to be displayed, so I'm not sure why I'm getting the crash?
333fred
333fred3w ago
You dereference coursename, then check for null That is not the correct order Same with instructorname
DaClownie
DaClownie3w ago
So if I wrapped this something like this:
private async void SaveCourseButton_Clicked(object sender, EventArgs e)
{
if (CourseName.Text is not null && InstructorName.Text is not null && InstructorPhone.Text is not null && InstructorEmail.Text is not null)
{
Course course = new Course(id, CourseName.Text, StartDate.Date, EndDate.Date, StatusPicker.SelectedIndex, InstructorName.Text, InstructorPhone.Text, InstructorEmail.Text, CourseNotes.Text, 0, 0);
var result = DataObjects.ValidateCourseInfo(activeTerm, course);
if (result.Length == 0)
{
SQLFunctions.AddNewCourse(course);
await Navigation.PopAsync();
}
else
{
await DisplayAlert("ERROR", result, "OK");
}
}
}
private async void SaveCourseButton_Clicked(object sender, EventArgs e)
{
if (CourseName.Text is not null && InstructorName.Text is not null && InstructorPhone.Text is not null && InstructorEmail.Text is not null)
{
Course course = new Course(id, CourseName.Text, StartDate.Date, EndDate.Date, StatusPicker.SelectedIndex, InstructorName.Text, InstructorPhone.Text, InstructorEmail.Text, CourseNotes.Text, 0, 0);
var result = DataObjects.ValidateCourseInfo(activeTerm, course);
if (result.Length == 0)
{
SQLFunctions.AddNewCourse(course);
await Navigation.PopAsync();
}
else
{
await DisplayAlert("ERROR", result, "OK");
}
}
}
Which i'm sure there's a much more elegant solution which I can work through later, but that wouldn't dereference it before checking for null, correct? and then I'd remove the null checks from the ValidateCourseInfo() Which I’m thinking the more elegant solution would be to disable the add course button until conditions are met. For now though that can wait
333fred
333fred3w ago
I would make ValidateCourseInfo actually resilient to null there Rather than what you are currently doing, which is trying to make it resilient to null, but too late Have you considered turning on nullable reference types?
DaClownie
DaClownie3w ago
I haven’t as that’s not something I’m aware of. Still learning and kinda fumbling my way through. I’d love to do some reading or learning if you have knowledge you’d like to share on what you’ve mentioned here or any articles that clarify what you’re suggesting clearly And thank you for your help so far! You’ve done more than enough already if you don’t want to do that additional request. I appreciate the guidance
333fred
333fred3w ago
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/nullable-reference-types The TLDR is that the compiler has built-in analysis that could have told you exactly where your null reference exception was occuring, before even running your application, because course.CourseName.Length == 0 || course.CourseName is null occurs in the wrong order
DaClownie
DaClownie3w ago
OH Literally out of order. I was thinking out of order meant before passing it to the method These are the little things my brain doesn’t catch yet. Nice little gotcha moment. I’ll read those articles this evening and see if a more elegant solution is readily accessible or if I should just reorder and move on for now but find other times to implement the nullable reference types
333fred
333fred3w ago
NRTs aren't really a solution to the problem; they're more about helping you validate that you don't have a problem before you run the code They can't fix things like this for you, they're a tool to point out the issue
DaClownie
DaClownie3w ago
Even better