How can C# constructor assign value to read only property? - c#

I wrote a class property with only get accessor, like:
public int MyProp { get; }
I cannot assign any value to MyProp, not even privately, via method inside my class, i.e. it's not like if I had a private set.
However, somehow, I can set a value to myProp using a constructor like:
public MyClass (int myProp) { this.MyProp = myProp; }
Is the constructor always immune to property accessor specifications? Are they valid only after the constructor runs?

When you create an auto-property the compiler automatically generates backing fields to support it. In the case of a readonly (get only) property this is still the case. Being able to assign to a get-only property in the constructor is simply syntactic sugar supported by the compiler. When you assign to the property, the compiler translates the code so that it assigns to the backing field instead.
For example, assume your constructor:
public MyClass(int myProp)
{
this.MyProp = myProp;
}
This is translated by the compiler to something akin to the following:
public MyClass(int myProp)
{
this._myPropBackingField = myProp;
}
The fact that you have no set accessor then prevents you from assigning to the property everywhere else.
In reality, the backing field recieves an "unspeakable" name that is illegal c# (but valid IL) thus preventing you from attempting to use the field directly. Your example actually looks like the following after the compiler has done its job:
public class MyClass
{
[CompilerGenerated]
private readonly int <MyProp>k__BackingField;
public int MyProp
{
[CompilerGenerated]
get
{
return this.<MyProp>k__BackingField;
}
}
public MyClass(int myProp)
{
this.<MyProp>k__BackingField = myProp;
}
}
Note that the constructor is actually assigning to the backing field <MyProp>k__BackingField directly rather than indirectly via the property's setter (since after all one does not exist).
See this SharpLab example.

Just think if the constructor is not allowed to initialize these values then what is the use of these values? It will always be the datatype default value like for int it will be 0. By using only get means we will not allow to change the value once it's initialized.
You can use readonly also, and it is thread-safe by default. but when you use a private set you have to handle the thread-safety explicitly.

Related

Can I define a custom getter for a C# auto-implemented property (a.k.a. auto backing field)?

Note: I know how to accomplish this without using auto-implemented properties, but I'm wondering if C# has a built-in way to do this.
Let's say I have this simple example of an auto-implemented property (a.k.a. auto backing field):
public class MyClass
{
public MyClass(){}
public string MyString { get; private set; }
}
Now, I would like to return a custom exception in the getter if the auto backing field is null:
public class MyClass
{
public MyClass(){}
public string MyString
{
get
{
return [backing field] ?? throw new Exception("MyString is null");
}
private set;
} = null;
}
Do newer C# versions support something like this? Perhaps there is some syntactic sugar that I can use in place of [backing field] to access the backing field that is automatically created by the compiler?
Note on putting an exception in the getter: I know it shouldn't be a habit. But Microsoft does it occasionally; for example, the property HttpContext.Request.Form will throw an exception if the request is not of the proper content-type.
No, you can not access to backing field in this way.
You must define backing field and validate it.
public class MyClass
{
public MyClass(){}
private string? _myString
public string MyString
{
get
{
return _myString ?? throw new Exception("MyString is null");
}
private set => _myString = value;
} = null;
}
As Fred said, its better to validate it outside of property.
I'm surprised noone mentioned the field keyword, it is exactly what you are asking for (what you would use instead of [backing field] in your example). It was supposed to be shipped with C# 10. It seems it is going to be shipped with C# 11 instead (?)
Search for Field Keyword here.
Put validation in the setter and/or ensure that the constructor sets a valid/non-null default value.
Or make the property nullable to hint to the customer that they have to account for a null value possibility.
Alternatively (but less optimally for multiple reasons), make the property private and add a method for accessing it.
Strongly advise against a property get directly throwing an exception. You or the consumer will dislike the results at some point.

Property Initializer cannot reference non-static field

I thought the new C# 6.0 property initializers like this.
public MyType MyProperty { get; } = new MyType(OtherProperty);
was the equivalent of this
private MyType _myVariable;
public MyType MyProperty { get { return _myVariable ?? _myVariable = new MyType(OtherProperty); } }
(that OtherProperty is available as part of the instance, not limited to being static)
But in the above first I get "field initializers cannot reference non-static field". Am I doing it wrong, or are property initializers just as limited as
public readonly MyType MyVariable = new MyType(NeedsStaticReference);
In your second example the field is set on first use.
The problem here, is the field intializer is set immediately before the constructor, and there is no guarantee the other property is set or constructed or what order this happens.
If you want to assign something on construction you will need to do it in the constructor
Fields (C# Programming Guide)
Fields are initialized immediately before the constructor for the
object instance is called. If the constructor assigns the value of a
field, it will overwrite any value given during field declaration.
A field initializer cannot refer to other instance fields.
And some more information
A field can optionally be declared static. This makes the field
available to callers at any time, even if no instance of the class
exists. For more information, see Static Classes and Static Class
Members.
A field can be declared readonly. A read-only field can only be
assigned a value during initialization or in a constructor. A
static``readonly field is very similar to a constant, except that the
C# compiler does not have access to the value of a static read-only
field at compile time, only at run tim
It's, actually, like this:
private readonly MyType _myVariable = new MyType(OtherProperty);
public MyType MyProperty { get { return _myVariable; } }
Thus, the issue.

C# Property with no setter - how can it get set from constructor?

How come you can set a get-only auto-property from a constructor? The code below shows how you can set the property from the constructor but using reflection shows that there really isn't a setter behind the scenes. How does it get set from the constructor call if the setter method doesn't even exist in the IL?
void Main()
{
var obj = new GetOnlyProperty("original value");
Console.WriteLine(obj.Thing); //works, property gets set from ctor
//get the set method with reflection, is it just hidden..?
//nope, null reference exception
typeof(GetOnlyProperty)
.GetProperty("Thing", BindingFlags.Instance | BindingFlags.Public)
.GetSetMethod()
.Invoke(obj, new object[]{"can't set me to this, setter doen't exist!"});
}
public class GetOnlyProperty
{
public string Thing { get; }
public GetOnlyProperty(string thing)
{
Thing = thing;
}
}
A read-only automatically-implemented property is converted by the compiler into a read-only field and a read-only property. Assignments to the property in the constructor are compiled as assignments to the underlying field.
So your code here:
public class GetOnlyProperty
{
public string Thing { get; }
public GetOnlyProperty(string thing)
{
Thing = thing;
}
}
is compiled into IL as if you'd written:
public class GetOnlyProperty
{
private readonly string _thing;
public string Thing => _thing;
public GetOnlyProperty(string thing)
{
_thing = thing;
}
}
... except that _thing is really given an "unspeakable name" that wouldn't be a valid C# identifier.
A read-only property (get only) has a backing readonly field, which as you probably know, can only be set in the constructor.
hence when you have object Property { get; }
this translates to
private readonly object _property;
public object get_Property(){return _property;}
and the compiler knows that if you set the property in the constructor to set the field directly
Because a read-only property should be assigned at a time or another, otherwise its value would always be the default value of the type, and it would be completely useless.
This is what constructors are for (beside other obvious reasons), to assign values to read-only fields.

properties in C#

Why are we able to write
public int RetInt
{
get;set;
}
instead of
public int RetInt
{
get{return someInt;}set{someInt=value;}
}
What is the difference between the two?
This feature is called Auto implemented properties and introduced with C# 3.0
In C# 3.0 and later, auto-implemented properties make
property-declaration more concise when no additional logic is required
in the property accessors. They also enable client code to create
objects. When you declare a property as shown in the following
example, the compiler creates a private, anonymous backing field
that can only be accessed through the property's get and set
accessors.
class Customer
{
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }
For your question
What is the difference between the two?
In your case, none. Since you are not doing anything while setting or retrieving the value, but suppose you have want to do some validation or want to perform other types of check then :
private int someInt;
public int RetInt
{
get
{
if (someInt > 0)
return someInt;
else
return -1;
}
set { someInt = value; } // same kind of check /validation can be done here
}
The above can't be done with Auto implemented properties.
One other thing where you can see the difference is when initializing a custom class type property.
If you have list of MyClass
Then in case of Normal property, its backing field can be initialized/instantiated other than the constructor.
private List<MyClass> list = new List<MyClass>();
public List<MyClass> List
{
get { return list; }
set { list = value; }
}
In case of Auto implemented property,
public List<MyClass> SomeOtherList { get; set; }
You can only initialize SomeOtherList in constructor, you can't do that at Field level.
How are these two different ?
There are different at least by 2 points:
In normal property you have to define a field before (someInt in your case)
In normal property you can set a breakpoint into the set/get modifiers, instead in auto property can not do that.
In other words: if you need "just property", use auto-properties, if you need more control over workflow (raise an event on set, debug, run other stuff inside), use "normal" properties.
These are auto implemented properties. Please see http://msdn.microsoft.com/en-us/library/bb384054.aspx for more info.
Basic reason why these were introduced was to reduce the overhead of programmer of creating a private variable like someInt which had little use than being used in a property.
Actually these aren't really different, in both cases you have a private field that corresponds to your property, but in the first case it is generated by the compiler and hidden.
If you need to use the variable behind the property quite often in your class, I think it's better to declare your property the old way (2nd one), because each time you will access it this will call the getter if you do it the "new" way.
If you only need it to be used from outside your class (or in most of cases), then you can go with the "new" way (1st one)

Do C# properties hide instance variables or is something deeper going on?

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; }

Categories