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.
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");
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
}
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.
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; }
In C#, I am defining a static field of a specific class. From within the class, I want to be able to display the name of the static field, pretty much like this:
public class Unit {
public string NameOfField { get { return ...; } }
}
public static Unit Hectare = new Unit();
If I now access:
Hectare.NameOfField
I want it to return:
Hectare
I know there is a static function System.Reflection.MethodBase.GetCurrentMethod(), but as far as I can tell there is no way to get the name of the instance containing this current method?
There is also the System.RuntimeFieldHandle structure, but I have not been able to identify any GetCurrentFieldHandle() method.
I am not sure if I am missing something obvious?
Any help on this is very much appreciated.
You should not count on variable names in you developments as they do not exits at runtime.
It's better to initialize Unit with a name directly:
public class Unit {
public Unit(string name)
{
NameOfField = name;
}
public string NameOfField { get; private set;} }
}
public static Unit Hectare = new Unit("Hectare");
Only way around this will be to store that information in the class:
public static Unit Hectare = new Unit("Hectare");
When your code is compiled all variable names are lost and replaced by internal references. There is no way to get that name again.
You can use Reflection to obtain class Fields and properties. Like below:
Suppose you have class with one property:
class Test
{
public static string MySupperField
{
get
{
return "Some symbols here";
}
}
}
......
You can read the property name in such way:
public string[] GetClassStaticNames(Type T)
{
string[] names;
System.Reflection.PropertyInfo[] props = T.GetProperties(); // This will return only properties not fields! For fields obtaining use T.GetFields();
names = new string[props.Count()];
for (int i = 0; i < props.Count(); i++)
{
names[i] = props[i].Name;
}
return names;
}
Hope this will help.
[EDIT]
Returning to your question - No you cant obtain name of current variable.
What you are asking about cant be done because of classes nature, they are objects in memory and reference to one object can be held in many variables, and when you are requesting value of instance field or property it will be actually performed operation with object in memory not with variable wich holds reference to that object. So obtaining name of variable wich holds reference to current instance have no sence
Thanks everyone who has taken the time to answer and discuss my question.
Just to let you know, I have implemented a solution that is sufficient for my needs. The solution is not general, and it has some pitfalls, but I'd thought I share it anyway in case it can be of help to someone else.
This is in principle what the class that is used when defining fields looks like:
public class Unit : IUnit {
public NameOfField { get; set; }
...
}
As you can see, the class implements the IUnit interface, and I have provided a public setter in the NameOfField property.
The static fields are typically defined like this within some containing class:
public static Unit Hectare = new Unit();
My solution is to set the NameOfField property through reflection before the field is used in the implementation.
I do this through a static constructor (that of course needs to be invoked before the Unit fields are accessed.
I use Linq to traverse the executing assembly for the relevant fields, and when I have detected these fields (fields which type implements the IUnit interface), I set the NameOfField property for each of them using the Any extension method:
Assembly.GetExecutingAssembly().GetTypes().
SelectMany(type => type.GetFields(BindingFlags.Public | BindingFlags.Static)).
Where(fieldInfo => fieldInfo.FieldType.GetInterfaces().Contains(typeof(IUnit))).
Any(fieldInfo =>
{
((IUnit)fieldInfo.GetValue(null)).NameOfField= fieldInfo.Name;
return false;
});
There are some shortcomings with this approach:
The static constructor has to be invoked through manual intervention before any Unit fields can be accessed
The NameOfField setter is public. In my case this is no problem, but it might be when applied in other scenarios. (I assume that the setter could be made private and invoked through further reflection, but I have not taken the time to explore that path further.)
... ?
Either way, maybe this solution can be of help to someone else than me.