When an object hold another object as a property and that property is by default null. Will that property be initialized if its own property's get accessed by code?
public User {
private _obj = null;
public Obj SomeObject {
get { return _obj ?? (_obj = new Obj()); }
set { _obj = value; }
}
public User() {
//do stuff
}
}
Code Being used.
User user = new User();
int x = user.SomeObject.SomeIntValue;
Would this initiate a new version of SomeObject if it was null?
-- Edit --
Applied #Kjartan suggestion to code.
This will indeed work. The first time the property will get accessed, _obj will be filled with the new instance (since it was null before). Next calls, you will return the same Obj instance that was initialized the first time.
This is a common way for creating some sort of "lazy-loading".
Should work. And as a side-note, just for brevity you could replace this:
get {
if(_obj == null)
_obj = new Obj();
return _obj;
}
...with this:
get { return _obj ?? (_obj = new Obj()); }
Related
I am building xamarin forms app, I am using jamesmontemagno settings plugin and I'm adding a property which list of a class. But the thing is I'm not able to add or insert to the list, every time I use method Add or Insert it jump into the get not the set and I can't understand why.
here is my code and thanks for the help in advance:
//adding an item to the list
private void order(Sales_Order_Items sale)
{
orderlist.Add(sale);
Settings.Usercartlist.Add(sale);
}
I can only set it by using this code
Settings.Usercarlist=orderlist;
the property in the settings file
public static List<Sales_Order_Items> Usercartlist
{
set
{
string listValue = JsonConvert.SerializeObject(value);
AppSettings.AddOrUpdateValue(myIntListKey, listValue);
}
get
{
string value = AppSettings.GetValueOrDefault(myIntListKey, string.Empty);
List<Sales_Order_Items> myList;
if (string.IsNullOrEmpty(value))
myList = new List<Sales_Order_Items>();
else
myList = JsonConvert.DeserializeObject<List<Sales_Order_Items>>(value);
return myList;
}
}
When adding an item, the actual object reference does not change. Only the value changes. This is not picked up by the getter or setter.
The only way to update after each item is to add the line you already have: Settings.Usercarlist=orderlist; after each operation.
I am using like the following way you can try that
Ex.
private static UserDetails _currentUser = null;
public static UserDetails CurrentUser
{
get
{
if (_currentUser == null)
{
string data = AppSettings.GetValueOrDefault(nameof(CurrentUser), string.Empty);
if (data != null)
_currentUser = JsonConvert.DeserializeObject<LoginResponse>(data);
}
return _currentUser;
}
set
{
string data = JsonConvert.SerializeObject(value);
AppSettings.AddOrUpdateValue(nameof(CurrentUser), data);
_currentUser = value;
}
}
I have a session helper so that my session vars are strongly typed:
public sealed class SessionHelper
{
private static HttpSessionState Session
{
get
{
return HttpContext.Current.Session;
}
}
public static List<TestObject> Tests
{
get
{
List<TestObject> objects = new List<TestObject>();
if (Session["Tests"] != null)
{
objects = (List<TestObject>)Session["Tests"];
}
return objects;
}
set
{
Session["Tests"] = value;
}
}
}
Now I am trying to add an item to theTestObjects List so I thought I could just do:
SessionHelper.Tests.Add(new TestObject("Test name", 1));
But when I step through the code and look at the SessionHelper.Tests after the above line is run, the list count remains at 0.
If I do:
List<TestObject> tests = SessionHelper.Tests;
tests.Add(new TestObject(testName, version));
SessionHelper.Tests = tests;
Then it works properly.
Why can't I add the test object directly to the SessionHelper?
Session["Tests"] is null when you start. Therefore SessionHelper.Tests returns a new, empty list; however, this new list is not in the session object yet. Therefore SessionHelper.Tests will return a new, empty list every time. Store the new list in the session object after creating it.
public static List<TestObject> Tests
{
get
{
List<TestObject> objects = (List<TestObject>)Session["Tests"];
if (objects == null)
{
objects = new List<TestObject>();
Session["Tests"] = objects; // Store the new list in the session object!
}
return objects;
}
set // Do you still need this setter?
{
Session["Tests"] = value;
}
}
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?
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>())
Note that if you hate the world (and your fellow programmers) 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 :-)
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>();
}
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;
}
}
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;
}
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>();
}
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.
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;
}
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>();
}
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.
I'm making a graphic control class Info which should display some text on screen. The text is some object's string. I'd like to be able to get that object's latest value from within an instance of Info class.
class Info
{
public string Text;
}
void Program()
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info();
wind1.Text = obj.name; // this just copies current value, but should be a reference or something
/* obj.name value changes several times before it's time to display it again */
// Info window drawing method
foreach (var item in Windows) // Windows is List<Info>
Draw(item.Text); // this doesn't get the latest value
}
How should I change the code so I can get the latest string value from within the drawing section?
Update: If you need something that'll work for any type, you'll have to use delegates. For example:
class Info
{
private Func<string> getText;
public Info(Func<string> getText)
{
getText = getText;
}
public string Text
{
get
{
return getText();
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(() => obj.name);
// Now do your stuff.
}
In this case, Info is given an anonymous function that returns a string. When you access its Text property, the function is evaluated to retrieve that string. How the string is retrieved, and where it comes from, is determined by the client code (i.e. the Program method). This way, Info doesn't rely on any particular type.
You could pass the ClassA object into your Info instance, so that it can get the value of.name itself.
Something like this, perhaps?
class Info
{
public Info(ClassA obj)
{
TheObject = obj;
}
public ClassA TheObject
{
get;
set;
}
public string Text
{
get
{
return TheObject.name;
}
}
}
void Program
{
ClassA obj = new ClassA();
obj.name = "Instance of ClassA";
Info wind1 = new Info(obj);
// Now do your stuff.
}
I currently have the following code:
public MyObject SessionStore
{
get
{
if (Session["MyData"] == null)
Session["MyData"] = new MyObject();
return (MyData) Session["MyData"];
}
set
{
Session["MyData"] = (MyObject) value;
}
}
I access it using SessionStore.ThePropertyIWant
I set it using SessionStore = SessionStore
This works; but is there a better way of accomplishing the same thing?
You don't need to cast in the setter, and can make the getter more concise :
public MyData SessionStore
{
get { return (MyData)(Session["MyData"]) ?? new MyData(); }
set { Session["MyData"] = value; }
}
SessionStore is fine but you could end up with alot of properties. I tend to add protected properties to base bases and access from there.
eg:
/// <summary>
/// Gets or Sets the Current Order Line
/// </summary>
protected OrderLine CurrentOrderLine
{
get
{
if (Session["CurrentOrderLine"] == null)
{
Session["CurrentOrderLine"] = new OrderLine(this.CurrentOrder);
}
return Session["CurrentOrderLine"] as OrderLine;
}
set
{
Session["CurrentOrderLine"] = value;
}
}
then it would appear as a property on your page if you inheriet from it.