In this tutorial by Josh Smith, a field is defined as readonly:
public class CustomerRepository
{
readonly List<Customer> _customers;
...
public CustomerRepository(string customerDataFile)
{
_customers = LoadCustomers(customerDataFile);
}
...
}
and later the readonly list, _customers, is updated:
public void AddCustomer(Customer customer)
{
if (customer == null)
throw new ArgumentNullException("customer");
if (!_customers.Contains(customer))
{
_customers.Add(customer);
if (this.CustomerAdded != null)
this.CustomerAdded(this, new CustomerAddedEventArgs(customer));
}
}
How this is allowed and what is the point of using readonly?
The List<Customer> variable itself (_customers) is readonly - that means you can't switch it out for an entirely different list, ensuring that everyone that's looking at it will always be seeing the same list. You can, however, still change the elements within that list.
From MSDN (https://msdn.microsoft.com/en-us/library/acdd6hb7.aspx):
The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class
You cannot assign new value to _customers field, but you still change the elements within that list.
_customers.Add(customer); does not update the list. This operator update the content of the list. If you want to update the list you must use something like _customers= .... And this is prevented by the readonly
The point of making the field readonly is that the reference cannot be changed. That means that you cannot write something like
_customers = null;
or
_customers = new List<Customer>();
Invoking the method .Add() accesses the collection through a method, and does not change the reference of the object.
This could be useful to prevent any NullReferenceException.
Related
I am not sure, but it seems i can not set a Property of a List?
The code in the (set) section does not get executed, debugger does not stop in the set when placing a break-point.
if a list property is dealt with differently? and if there is a link of some reading on this subject.
class test
{
public test()
{
id = new List<string>();
_id = new List<string>();
}
private List<string> _id;
public List<string> id
{
get { return _id; }
set
{
_id = value;
}
}
}
test t = new test();
t.id.Add("one");
The code in the (set) section does not get executed, debugger does not stop in the set when placing a break-point.
It appears that your question is, "why is the set accessor not called when I do: t.id.Add("one");"
The reason is simply that the set accessor is for the List itself. Your code is not setting t.id to a new List<string>, rather it is calling the .Add method of the object returned from the t.id property.
So the execution would look something like:
The get accessor is called when you do t.id, and it returns the instance of _id
The .Add method of _id is then called, and the string "one" is added to the private backing field _id
Note that in your existing code, the set does get called from the constructor, when you explicitly set the id to a new List.
You've stated that your goal is "to change some other properties when I add an item to id". There are a few ways to do this, but probably the simplest to understand and implement is:
In the get accessor for the list, return a copy of the list. This prevents clients from adding an item directly through the Add method. Also note that there is no need for a set accessor.
Provide a separate AddId method on your class, which is what the clients would have to call to actually add an item. This is where you have the opportunity to do something else when items are added to the list.
For example:
class Test
{
private readonly List<string> id = new List<string>();
// Return a copy of our private list
public List<string> Id => id?.ToList();
public void AddId(string newId)
{
id.Add(newId);
// do something else here when we add a new item
}
}
Note that this might cause some confusion for clients of your class, because they can still do test.Id.Add("invalid item"); and they won't get any error, but it also won't add anything to the private list. If they want to add something to the list, they have to call the AddId method:
t.AddId("one");
How is this code able to compile and run error free?
private void queueToolStripMenuItem_Click(object sender, EventArgs e)
{
//Class name MDPlayer
Playlist.QueueList.Add(tempPlayList[songView.SelectedIndex]);
Playlist.GetQueue = null;
QueueCombobox.Items.Clear();
foreach (PlayListData pld in Playlist.QueueList)
{
QueueCombobox.Items.Add(pld.Track);
}
}
class Playlist
{
private static List<PlayListData> queueList = new List<PlayListData>();
public static List<PlayListData> QueueList
{
get { return queueList;}
}
}
How am I able to add to queueList that is private through the public property QueueList that doesn't even have a setter?
You are able to call methods on the return value of a property getter.
Your property getter returns a List<>. List<> defines the Add method. Thus you can call the Add method on the List<> that you asked for.
Note that you can not assign a new value to the listQueue from outside the PlayList class because it is private.
Also, you can not assign a new value to the ListQueue property because it has no setter accessor.
This will fail: PlayList.QueueList = new List<PlayListData>();
Because you're adding to the list via the getter. You're not setting the underlying private variable to anything. You can do QueueList.Add(), but not QueueList = newList.
When you get a value from the getter, it returns the whole class and that class is alterable. You only need a setter when you want to set the whole variable to an entirely different class.
Summary
You only need to use a setter when setting the whole variable.
Can
Playlist.QueueList.Add(tempPlayList[songView.SelectedIndex]);
Cannot
Playlist.QueueList = new List<PlayListData>();
My example:
class MyClass
{
public int a = 1;
public static List<MyClass> list = new List<MyClass>();
}
class Program
{
static void Main(string[] args)
{
MyClass.list.Add(new MyClass() { a = 5 });
MyClass.list.Add(new MyClass() { a = 10 });
foreach (MyClass item in MyClass.list) Console.WriteLine(item.a);
Console.ReadKey();
}
This code works, and shows that my list, which is statically defined within the MyClass class itself, is populating as I'd expect.
Is there any reason not to define my list in this manner?
Such a solution is used sometime, f.e. to implement the Singleton or Register-Resolve patterns.
But you should keep in mind that it's not well suited for multithread environment. Typically, a static collection should be private, and access methods (including property getter and setter) should be synchronized.
In additional, static fields/properties are difficult to an unit testing.
Actually this code shows a lot of sign of (very) bad desing.
First of all one better doesn't make fields public. All other classes/object can now alter the value of that variable in objects. Perhaps you don't see much problems with that, but imagine that at one point in time you want to restrict the range of values that variable can have, or that it depends on the value of another field. Properties (with getters and setters) and methods are used to shield an field from external usage, they need to guarantee that the object always remains in a valid state.
Next about the list, again don't make such lists public - unless you are confident that there is no problem -. But furthermore using statics is by some researchers considered to be bad design as well. The list maintains a state, but since it is static, this is a global state. Global states are problematic since they don't allow (easy) unit testing, and can become problematic if for some reason the list should be not that global.
In case you really want to make some access point for data, you can perhaps consider making a class that stores such list and pass it around in your program.
There are a few exceptions, for instance the Flyweight pattern where one indeed maintains a global state. Those examples are merely used to increase performance. For instance:
public class FlyWeightInstance {
private int value; //<- private field
private static Dictionary<int,FlyWeightInstance> dic = new Dictionary<int,FlyWeightInstance>(); //<- private static cache
private int FlyWeightInstance (int value) { // <-- private constructor
this.value = value;
}
public static FlyWeightInstance (int value) {
FlyWeightInstance res;
if(!dic.TryGetValue(value,out res)) {
res = new FlyWeightInstance(value);
dic.Add(value,res);
}
return res;
}
}
I have the following sealed class. I'm trying to return the list as a ReadOnlyCollection. Tried a couple of things but I'm not getting the hang of this. So how do I return or cast the list to the readonly collection?
public sealed class UserValues
{
private readonly List<UserValue> _Values = new List<UserValue>();
public ReadOnlyCollection<UserValues> Values
{
get
{
return _Values;
}
}
}
You're getting the compile-time error because a List<UserValue> is not a ReadOnlyCollection<UserValue>, nor is it implicitly convertible to that. (I assume you meant ReadOnlyCollection<UserValue> instead of ReadOnlyCollection<UserValues> by the way?)
It's probably simplest to use List<T>.AsReadOnly - but you might as well only create it once:
public sealed class UserValues
{
private readonly List<UserValue> values = new List<UserValue>();
private readonly ReadOnlyCollection<UserValue> valuesView;
public UserValues()
{
valuesView = values.AsReadOnly();
}
public ReadOnlyCollection<UserValues> Values { get { return valuesView; } }
}
The ReadOnlyCollection<T> really is just a view - so changes to the underlying collection will be visible through the view.
Try:
return new ReadOnlyCollection<UserValue>(_Values);
Edit:
Given what you've said to Jon, your code doesn't make sense. Your get is referencing a type of List<UserValue>, but you're wanting to convert it to a type of ReadOnlyCollection<UserValues>, which cant be done - that's 2 collections of 2 different types.
We'll need more information to help you answer this question. Are you wanting your UserValues class to return a collection of UserValues types, or a collection of UserValue types? Your code implies UserValue, but your follow on comments state UserValues. Are you sure your supervisor didn't make a typo?
If not, you'll need some internal collection like so:
private readonly List<UserValues> _MoreValues = new List<UserValues>();
And then return that, in the syntax that I (or others who have answered - all the answers given are valid for converting a List to a ReadOnlyCollection) have shown.
Note that my code compiles targeting .Net 3.5, presuming that the types are compatible (meaning ReadOnlyCollection<UserValue> wraps List<UserValue>, or both are UserValues).
_Values is a List<UserValue>, not a ReadOnlyCollection<UserValue> (they're not related, as far as the compiler knows), so you can't return _Values directly. You can either create a ReadOnlyCollection<T> from your list and return that, like:
private List<UserValue> _Values = [whatever];
private ReadOnlyCollection<UserValue> _ValuesWrapper;
public UserValues()
{
_ValuesWrapper = _Values.AsReadOnly();
}
public ReadOnlyCollection<UserValue> Values
{
get { return _ValuesWrapper; }
}
...or, if you're just looking for a read-only way of accessing your collection and don't need a ReadOnlyCollection<UserValue> object specifically, you could change your property to return a read-only interface that List<T> implements, and your application could use that instead. .NET 4.5 introduced some read-only collection interfaces that are great for this kind of thing:
public IReadOnlyList<UserValue> Values
{
get { return _Values; }
}
Consider the class:
public class foo
{
public object newObject
{
get
{
return new object();
}
}
}
According to MSDN:
Properties are members that provide a flexible mechanism to read,
write, or compute the values of private fields. Properties can be used
as though they are public data members, but they are actually special
methods called accessors. This enables data to be accessed easily
And:
Properties enable a class to expose a public way of getting and
setting values, while hiding implementation or verification code.
A get property accessor is used to return the property value, and a
set accessor is used to assign a new value. These accessors can have
different access levels. For more information, see Accessor
Accessibility.
The value keyword is used to define the value being assigned by the
set indexer.
Properties that do not implement a set method are read only.
while still providing the safety and flexibility of methods.
Does this therefore mean that at some point in time the value of the newObject property has a reference to the returned new object?
edit removed readonly from property
edit2 also would like to clarify that this is not the best use for a property but its done to try and illustrate the question more effectively.
You return a new object on each access to the property and that is not the expected behavior of properties. Instead you should return the same value each time (e.g. a value stored in a field). A property getter is simply glorified syntax for a method that returns a value. Your code compiles into something like this (the compiler creates a getter by prefixing the property name with get_ which is then emitted as IL):
public class foo
{
public object get_newObject()
{
return new object();
}
}
Each call to the getter will create a new object that foo doesn't know about or has access to.
Does this therefore mean that at some point in time the value of the newObject property has a reference to the returned new object?
No.
Property using a backing field:
class Foo {
readonly Object bar = new Object();
public Object Bar { get { return this.bar; } }
}
Using automatic properties:
class Foo {
public Foo() {
Bar = new Object();
}
public Object Bar { get; private set; }
}
A property is accessed using the same easy syntax as a public field. However, by using a property you can add code to the getter and the setter allowing you to do stuff like lazy loading in the getter or validation in the setter (and much more).
Under the hood, your property will simply be calling a function named get_newObject() that looks like this:
public object get_newObject()
{
return new object();
}
Since that is the case, it will always return a new object every time it is invoked.
If you want to retain a reference to the object, then I would recommend creating a private field to hold the data and having the property access that field, like so:
private object myObject;
public object newObject
{
if(myObject == null)
{
myObject = new object();
}
return myObject;
}
Since your property doesn't define set, and your field is private, newObject is basically eradonly outside of the containing class.
Properties in C# are "syntactic sugar". The code within the get block of a property is in fact put into a hidden get_PropertyName() method, and the set block into a hidden set_PropertyName() method. In the case of your code, the following method will be created:
public object get_newObject()
{
return new object();
}
You can see these hidden methods if you view the compiled assembly using Reflector, or ildasm.
When the property is used, the C# compiler converts any "get" accesses of your property into calls of the get_newObject() method. As an example:
If you were to write the following:
var foo = new foo();
var aNewObject = foo.newObject;
The compiler would convert that to:
var foo = new foo();
var aNewObject = foo.get_newObject();
So, in answer to your other question, the newly created object returned when someone "gets" the property won't be stored within your foo instance, the caller will simply get a new object every time.
Not exactly. Properties are just syntactic sugar so that you don't have to write accessor methods (like Java).
So this:
private int _myInteger;
public int MyInteger
{
get { return _myInteger; }
set { _myInteger = value; }
}
is equivilant to this:
private int _myInteger;
public int GetMyInteger()
{
return _myInteger;
}
public void SetMyInteger(int value)
{
_myInteger = value;
}
and it gets better with this, which is also equivilant:
public int MyInteger { get; set; }