In the code below I have a property in base class which returns a list of custom objects. In the parent class I override this property and in the definition of the override I access the reference to the list of custom objects from the base class and add 2 objects to it.
Before returning I put a breakpoint in the code and check the content of the base property and notice that the two new objects are not there. Then I tried storing the reference to the list of objects in the base class locally and added two objects in the list again. I notice that in the local reference the 2 new objects have been added.
However, using both methods I'm pointing to the same reference so I should be able to add objects by referring to the base.TestProperty. Any idea why that won't work?
public override List<CustomObject> TestProperty
{
get
{
List<CustomObject> temp = base.TestProperty;
CustomObject obj1 = new CustomObject()
{
Name = "My Name"
};
CustomObject obj2 = new CustomObject()
{
Name = "Your Name"
};
// Adding to the base list
base.TestProperty.Add(obj1);
base.TestProperty.Add(obj2);
// Adding to temp list, which still points to the base list
temp.Add(obj1);
temp.Add(obj2);
// Base object doesnot contain obj1 and obj2, but the temp object does.
return base.TestProperty;
}
}
This isn't really the specific answer you're looking for, but... you should really reconsider your design.
You've got a property in your subclass... and getting that property changes your class' values. That's extremely counterintuitive. It's not like you'd expect:
Color bgCol = Color.Red;
int red = bgCol.R;
... that second statement to change values of your variable just by accessing one of its properties! How confused would you be if, when running that second statement, it changed the contents of bgCol to yellow?
My advice? Have the base class return what it's supposed to - forgetting about the subclass. And if your subclass needs to add values to that result? Then have it add the values when the subclass's property is called - but only to the result it's passing back - don't have it mess with the base object's properties at all.
public override List<CustomObject> TestProperty
{
get
{
List<CustomObject> objectsFromBase = base.TestProperty;
List<CustomObject> objectsFromThisClass = GetMySubclassCustomObjects();
List<CustomObject> retVal = new List<CustomObject>();
retVal.AddRange(objectsFromBase);
retVal.AddRange(objectsFromSubclass);
return retVal;
}
}
private List<CustomObject> GetMySubclassCustomObjects()
{
// your code for those two CustomObjects, and returning them from a list
}
Related
Just because of interest ...
Given I have a statically defined List<Car> CarsList, and an object of type Car, can I instantiate a new car and add it to the list, while getting a reference to it, in a one-liner?
If I instantiate a car like c1 = new Car("Honda Civic"), it seems I cannot add the car to the list in its constructor:
public Car (string name) {
_name = name;
CarsList.add(this); // adds null
}
And it seems that I can not do it the other way round either:
c1 = CarsList.add(new Car("Honda Civic")); // does not work, list.add does not return a reference to the newly added object.
Is there any way to achieve what I want?
If I really wanted such a construct, I would add an extension method to List<T> which adds the item to the list and returns the item. I would call that extension method With().
That having been said, adding your Car to the CarsList from within the constructor of Car should not add null. You must be doing something fishy there.
Code:-
(Note:- here I'm using read-only word means that property has only get accessor.)
Class Test
{
public List<string> list {get;}
public string name{get;}
public Test ()
{
list =new List<string>();
}
}
Main()
{
Test test =new Test();
test.list.add("c#"); //no error
test.name="Jhon"; //here I get compilation because property name is read-only
}
If you see above snippet. Test class contain two property which is name and list. In main method I'm creating object of test class to access these properties. So if you see if I try to set value to name property then I'll get compilation error because name property is read only. Similarly if you see another property 'list' that is also read-only if I use add property of List class then without error I'm able to add in list.
So I'm not getting how this happen.
That's because the set would refer to setting the List object, the actual instance of the collection. The List itself, when returned, is not readonly. If you want it to be readonly, you can do something like:
private List<string> list;
public ReadOnlyCollection<string> List {get => list.AsReadOnly()}
You have a misunderstanding of how a "read only" property would work.
If your code looked like this:
Test test = new Test();
test.list.Add("c#"); //no error because you are not 'setting' the object
test.list = new List<string>(); //Error here because you ARE setting the object
Add() is just a method of a List<T>, you are modifying the object not setting the property to something else.
If you want your collection to be "read only" you can use the ReadOnlyCollection interface. You can manage a private list internally and only expose through the public ReadOnlyCollection. Your desired functionality was never made clear so I wouldn't know what to suggest beyond what I have.
This is because in case of a string you return a copy of the instance - you can not assign to it.
Why .NET String is immutable?
In case of a List<T> you return a reference to an instance, which is not constant in your case - it is possible to change it.
To prove that yourself, you can do something like :
class Test
{
private string val;
public ref string Val {get {return ref val;}}
}
void Main()
{
Test t = new Test();
t.Val = "a";
Console.WriteLine("t.Val is - " + t.Val);
}
Observe special ref keyword I used in string property, to denote that string reference has to be returned and not a copy of it.
C# Concepts: Value vs Reference Types (Joseph Albahari)
public List<string> list {get;}
That means, it causes the error if you do the same action with name.
test.list = new List<string>();
test.list to get the list object and you call the method Add of the list object. So it's normal.
Well, i have a simple List of classes which might get updated during run-time the problem is that when i set a property it doesn't update in the List.
Code:
class Foo
{
public List<Link> Link => new List<Link>();
public Foo()
{
//... Code that adds items to the list.
var addr = Link.Find(_ => _.Valid).Use().Address;
//here if i break and look at the Link list it must contain an item with Valid = false, yet it doesn't
}
}
public class Link
{
public Uri Address { get; set; }
public bool Valid = true;
public Link Use()
{
Valid = false;
return this;
}
}
i know that it must update because i am using a reference of that item in the list, yet for some unknown reason it doesn't.
Each time you are getting the value of Link property new list instance is created and returned. You should initialize property only once and return the same instance of the list when you are getting property value:
public List<Link> Link { get; } = new List<Link>();
Why your code do not work? Think about what happens when you add two items this way and perform a search:
Link.Add(new Link());
Link.Add(new Link());
Link.Find(...)
You are calling getter of Link property which creates new instance of the list and returns that empty instance.
You are adding first Link object to the instance of the list which you are received in step #1.
You are calling getter of Link property again, which creates new instance of the list (yes, another instance) and returns that new instance (empty list).
You are adding second Link object to the new empty list return on step #3.
You are calling getter of Link property which creates third instance of the list (again, empty) and returns that instance.
You are calling Find method of the empty list returned on step #5.
Maybe it's just a misunderstanding but this is a big question for me. Let me explain it:
According to reference a property is a mechanism and not a field. A mechanism that provide read and write functions for a field, and according to this we can create a read-only, write-only or read-write property by using get and set accessors.
Now the implementation is here:
public class Foo
{
private List<string> _bar;
public List<string> Bar
{
get
{
return _bar;
}
}
public Foo()
{
_bar = new List<string>();
_bar.Add("string1");
}
}
In Foo class we have a read-only property (Bar) that consists of one string.
Now lets add a driver for this class:
static void Main(string[] args)
{
Foo fooObj = new Foo();
fooObj.Bar.Add("string2");
foreach (string s in fooObj.Bar)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
And here is the big question mark:
Why the Bar property is not read-only?
output:
srring1
string2
I know how to create a read-only collection (my question is not why List<T> is not read-only) and I need a explanation about read-only properties.
Well the Bar property is read only i.e. it can't be directly set
fooObj.Bar = new List<string>(); // compiler error
However, the data returned by that property isn't
fooObj.Bar.Add("..."); // is fine
The point to understand is the modifier on a property dictates how it can be accessed from the object, it has no direct affect on the underlying data of the property. Therefore, returning a reference type from a read-only property is the exact same as returning a reference type from a read/write property.
In your example, if you wanted the Bar to be read-only then you could return a ReadOnlyCollection<T> which is an immutable collection, rather than a List<T>.
private List<string> _bar;
...
public void Add(string item)
{
_bar.Add(item);
}
public IEnumerable<string> Bar
{
get { return new ReadOnlyCollection<string>(_bar); }
}
This would keep control of the list with the containing object but allow you to return a readonly copy of the list itself.
Okay,
A List<T> is a reference type.
So, a property
List<string> SomeList
{
get
{
// ...
}
}
is a read-only property, you cannot set the SomeList to a different List<string>. Essentially,
SomeList = new List<string>();
will not compile.
As you note, making a property of a reference type read only does not make that type read only.
If you want a read only list I'd suggest,
IReadOnlyList<string> SomeList
{
get
{
// ...
}
}
Because the getter method of your Bar property returns the list, and then you are mutating that list.Omitting the setter method only prevents you to assign a new list directly like this:
fooObj.Bar = new List<string>();
If you want to make it immutable you can change return type of your property to IEnumerable<string> instead.. Though you can still cast it to list and then mutate...
The Bar property is read-only. You can only read the list Bar points to - you cannot make Bar point to some other list.
However, the list itself is mutable. You can add or remove items from it.
Eric lippert calls this "shallow immutability" in his blog post Immutability in C# Part One: Kinds of Immutability. The property is read-only, but its contents can change.
I'm trying to understand how the line:
private Queue<IProductable> inventory { get; set; }
It is used in the entire code below. I'm only used to seeing properties defined using simple types; so, this really confused me. Also, I'm curious why the constructor for the class Factory (below) uses:
inventory = new Queue<IProductable>();
Instead of:
Queue<IProductable> inventory = new Queue<IProductable>();
My understanding is when you instantiate an new object, you should do: CLASS/TYPE newObjectName = new CLASS/TYPE. Is the constructor even instantiating a new "inventory" object? If so, why don't I have to specify what type the object "inventory" is (in order to use it to invoke methods from the generic Collections class, Queue).
Anyway, below, is the code. I'm hoping someone can explain this in the easiest possible way for me to comprehend/remember when I need to do something similar in the future.
namespace codeExample
{
class Factory
{
private Queue<IProductable> inventory { get; set; }
public Factory()
{
inventory = new Queue<IProductable>();
}
public IProductable GetOldestItem()
{
IProductable oldestItem = inventory.First();
return oldestItem;
}
public IProductable GetNewestItem()
{
IProductable newestItem = inventory.Last();
return newestItem;
}
public void Add(IProductable productToAdd)
{
inventory.Enqueue(productToAdd);
}
}
}
My understanding is when you instantiate an new object, you should do: CLASS/TYPE newObjectName = new CLASS/TYPE. Is the constructor even instantiating a new "inventory" object?
If the type were included then it would be creating a new local variable. Currently the code is not creating a new variable, it is using the property instead, which is a part of that class's instance data (at least in this case). The property (in this specific context) acts almost exactly like a private field would. It is creating a variable that exists for the lifetime of the whole object, not just one method.
Is the constructor even instantiating a new "inventory" object?
It's creating a new queue object, yes. The property definition defines where a queue may be stored, but it doesn't create an actual queue. The constructor actually creates a queue (which is empty) and assigns is to the variable.
The private Queue<IProductable> inventory { get; set; } declares an auto-implemented property, but it could as well have been a field:
private Queue<IProductable> inventory;
This declares a private instance variable, which you can access from any method in this class, but not from derived classes or from outside the class.
Your code assigns a value in the constructor, which is always run before other code in the class:
inventory = new Queue<IProductable>();
So now from everywhere in this class you can access inventory.
I'm only used to seeing properties defined with simple types; so, this
really confused me
Why? You can define properties of any type.
Also, I'm curious why the constructor for the class Factory (below)
uses:
You can't define the type of the property again, it's already available in the current scope because it's a class property. Its type is defined at the line private Queue<IProductable> inventory { get; set; }
My understanding is when you instantiate an new object, you should do:
CLASS/TYPE newObjectName = new CLASS/TYPE
No, here is a simple counter-example in two lines:
MyType myVariable;
...
myVariable = new MyType();
private Queue<IProductable> inventory { get; set; }
is an auto property.
it's equivalent to
private Queue<IProductable> _inventory;
public Queue<IProductable> Inventory
{
get { return _inventory; }
set { _inventory = value; }
}
Thus, you just declared a member inventory, and later on you instantiate a Queue<IProductable> and store its reference to the auto property inventory.
inventory = new Queue<IProductable>();
private Queue<IProductable> inventory { get; set; } is an automatic property. The implementation of get/set are provided by the compiler.
vs
Queue<IProductable> inventory = new Queue<IProductable>();
Now, inventory is a field. Properties have backing stores and are smarter than fields. They allow a programmer to do work during get/set operations.
Is the constructor even instantiating a new "inventory" object?
Yes, in the example the constructor is setting the hidden variable (backing store).
If so, why don't I have to specify what type the object "inventory" is
(in order to use it to invoke methods from the generic Collections
class, Queue).
Because you are not declaring a new variable in the constructor. We are setting a property.
Here you could use a field instead of a property. However, I would expect an "advanced class"/Factory to use Dependency Injection and thus a public property would make sense in such a case. (Maybe you simplified the original code?)