I have this simple code:
public static void Main(String[] args)
{
Data data = new Data { List = { "1", "2", "3", "4" } };
foreach (var str in data.List)
Console.WriteLine(str);
Console.ReadLine();
}
public class Data
{
private List<String> _List = new List<String>();
public List<String> List
{
get { return _List; }
}
public Data() { }
}
So when I'm creating a Data class:
Data data = new Data { List = { "1", "2", "3", "4" } };
The list was filled with strings "1", "2", "3", "4" even if it had no set
.
Why is this happening?
The error "Cannot assign to read only property of object" occurs when we try to change a property of an object that has been frozen or when a property has been defined with Object.defineProperties (). To solve the error, create a copy of the object or array, or set the property to writable.
Read-only properties may have initializers and may be assigned to in constructors within the same class declaration, but otherwise assignments to read-only properties are disallowed. ( Source) But what confuses me is the compiled output. See an example on the TS Playground.
However, a read-only dependency property can be used as a property trigger in a style. For example, IsMouseOver is commonly used to trigger changes to the background, foreground, or other visible property of a control when the mouse is over it.
As you can see the initially (readonly) property is overwritten without any warning from TS at compile time. I guess this is intentional, because the language behaves the same all the time and there are less edge cases. EDIT: There is also a "sugarized" way to initialize a class with properties in TypeScript (I guess you know that but anyway):
Your object initializer (with collection initializer for List
)
Data data = new Data { List = { "1", "2", "3", "4" } };
gets turned into the following:
var tmp = new Data();
tmp.List.Add("1");
tmp.List.Add("2");
tmp.List.Add("3");
tmp.List.Add("4");
Data data = tmp;
Looking at it this way it should be clear why you are, in fact, adding to string1
and not to string2
: tmp.List
returns string1
. You never assign to the property, you just initialize the collection that is returned. Thus you should look at the getter here, not the setter.
However, Tim is absolutely correct in that a property defined in that way doesn't make any sense. This violates the principle of least surprise and to users of that class it's not at all apparent what happens with the setter there. Just don't do such things.
That is how collection initializers work internally:
Data data = new Data { List = { "1", "2", "3", "4" } };
It is basically equal to
Data _d = new Data();
_d.List.Add("1");
_d.List.Add("2");
_d.List.Add("3");
_d.List.Add("4");
Data data = _d;
And _d.List
uses string1
in getter.
[*] More details in C# specification $7.6.10.3 Collection initializers
Change your code to this:
Data data = new Data { List = new List<string>{ "1", "2", "3", "4" } };
And string1
will be empty and string2
will have four items.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With