Reputation: 5281
Using .Add
to add an instance of a class to a generic list is not working.
To illustrate the problem, here are two simple example classes:
public class WorkOrder
{
private List<Note> _Notes;
public List<Note> Notes
{
get
{
return _Notes ?? new List<Note>();
}
set
{
_Notes = value;
}
}
}
public class Note
{
public string NoteText { get; set; }
public System.DateTime Time { get; set; }
public string User { get; set; }
}
You may notice the coding in get
on the WorkOrder.Notes
property. I put this in so the property wouldn't be initialized with a null value (ref an answer to another question I posted on SO here).
To utilize these classes:
public void Test()
{
WorkOrder tempWorkOrder = new WorkOrder();
Note tempNote = new Note()
{
User = "Aaron",
Time = DateTime.Now,
NoteText = "Work Order pulled from CSV Excel report."
};
tempWorkOrder.Notes.Add(tempNote);
}
I would expect the last line in Test()
to add tempNote
to the list of Note
in tempWorkOrder
. However, tempWorkOrder.Notes
is null after this line completes. No errors or exceptions are thrown.
I'm using VS2013 Express.
What am I doing wrong?
Upvotes: 7
Views: 16071
Reputation: 111840
private List<Note> _Notes;
public List<Note> Notes
{
get
{
return _Notes ?? new List<Note>();
}
set
{
_Notes = value;
}
}
The get
is wrong. It should be:
get
{
if (_Notes == null) {
_Notes = new List<Note>();
}
return _Notes;
}
because otherwise you don't save the new List<Note>()
you created and every time you use the get
you recreate it (the get
returns a new List<Note>()
but doesn't modify _Notes
, so every get
checks _Notes
, see it's null
and return a new List<Note>()
)
You can compact the get
to:
return _Notes ?? (_Notes = new List<Note>());
(see Ternary/null coalescing operator and assignment expression on the right-hand side?) I don't hate enough the world (and my fellow programmers) to do it :-)
Upvotes: 19
Reputation: 21
It should be possible to use the null-coalescing assignment if you are using C# 8, like so:
get => _Notes ??= new List<Note>();
With brackets:
get
{
return _Notes ??= new List<Note>();
}
Upvotes: 1
Reputation: 6522
Late to the party, you can create a small extension method which can guard against null or empty list:
public static bool NotNullAndEmpty<T>(this IEnumerable<T> source)
{
if (source != null && source.Any())
return true;
else
return false;
}
Also, if you are using database, then its advisable to use IEnumerable
and do all modifications with IEnumerable
. Once done, call .ToList(
) which will result in a single call to the database.
Upvotes: 0
Reputation: 1323
public class WorkOrder
{
public List<Note> Notes {get;set;}
public WorkOrder()
{
Notes = new List<Note>();
}
}
But in C# 6.0 you should be able to do the following:
public class WorkOrder
{
public List<Note> Notes {get;set;} = new List<Note>();
}
Upvotes: 0
Reputation: 7944
You're not initializing _Notes
.
So while you get a List<Note>
back when _Notes
is null, it is not assigning the object to _Notes
. Each time you access the public property, it is returning a different List<Note>
which is why the Add()
call appears to not work.
You should rather use:
get
{
if (_Notes == null)
_Notes = new List<Note>();
return _Notes;
}
Upvotes: 1
Reputation: 2793
The problem is your get method:
get
{
return _Notes ?? new List<Note>();
}
Since you don't assign the reference of the object you're creating to _Notes
, it keeps being null, and you assigned to a list that isn't referenced anywhere else.
This is what you can do instead:
get
{
if (_Notes == null)
_Notes = new List<Note>();
return _Notes;
}
Upvotes: 0
Reputation: 8551
In the getter for Notes
, you're doing nothing to save a reference to the newly-created list. Therefore, every time you access that getter, you'll get a fresh, empty list. So this:
tempWorkOrder.Notes.Add(tempNote);
...is adding tempNote
to a List<Note>
that is immediately thrown away.
Upvotes: 0
Reputation: 2376
You never assign _Notes
Do this instead
private List<Note> _Notes;
public List<Note> Notes
{
get
{
if(_Notes == null)
_Notes = new List<Note>();
return _Notes;
}
set
{
_Notes = value;
}
}
Upvotes: 1
Reputation: 2289
You have not created the list yet there. You need to add a constructor to the WorkOrder
as you cannot add to a collection that does not exist. This way, whenever you create a Work Order, you will have an empty list in the `_Notes' field.
It would look something like this:
WorkOrder(){
_Notes = new List<Note>();
}
Upvotes: 2