Property Initializer cannot reference non-static field - c#

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.

Related

Why does C# not warning about non-nullable long field?

Why do I not get a non-nullable warning (or some other warning) for FieldTwo not being set in the constructor? I'm using .Net 5.0 and Nullable option is set to true in the project file.
public class MyClass
{
public string FieldOne;
public long FieldTwo;
public MyClass (string p1, long p2)
{
FieldOne = p1;
// FieldTwo is not set. Where is the non-nullable warning!?
}
}
long is a value type and cannot be null. So there is no reason for warn about null. What I suspect you want is a field not initialized warning.
If a private field is never assigned, it causes a CS0649 warning. However, if the field public, or is modified anywhere in the class, this warning is not raised. For example, the following would be perfectly acceptable code, and should not give a warning:
public class MyClass{
private long myLong;
public void Increment() => myLong++;
}
If the field should only be set from the constructor you should declare it as readonly. However, public readonly fields does not trigger a warning, even if they probably should. See Why do I NOT get warnings about uninitialized readonly fields?.
long is a value type and can't be null. Value types are always initialized when declared with a default value, in this case 0. You'd have to change the field type to long? if you wanted to store a null
Those fields aren't properties anyway. This isn't just semantics. Fields are implementation details, even public fields. They aren't considered part of a class's API surface. Properties are part of the API, they get serialized by default by all serializers (fields don't) and guarantee In fact having public fields is a code smell.
To ensure all properties are initialized you can use a record type instead of a class :
public record(string PropertyOne, long PropertyTwo);
This generates a class with init-only properties for PropertyOne and PropertyTwo and a constructor that requires values for all properties. Along with equality operators, deconstructors and a ToString() implementation that returns all properties in the form of a JSON string.

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

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.

Default and custom constructor

I have a simple question.
Assume that I have class like below.
public class DamageToDeal
{
public bool enabled;
public float value;
public TDValue type;
public DamageToDeal() { }
public DamageToDeal(bool _enabled, float _value, TDValue _type)
{
enabled = _enabled;
value = _value;
type = _type;
}
}
I read that if I have custom constructor the default is not automaticaly generetared
Do I have to initialize fields myself with default values(0, null) or default constructor with empty body will do it anyway?
Or if the default constructor is initializing fields even if he has empty body ?
Memory allocated to a new class instance is cleared by the memory allocator. You only have to ensure that any fields you want to have a non-default value is assigned.
This is documented here: Fundamentals of Garbage Collection:
Managed objects automatically get clean content to start with, so their constructors do not have to initialize every data field.
You do not need an empty parameterless constructor for this to happen. You would only add that constructor if you actually want to call it and that makes sense for the type.
Also note that any field declarations that also states an initialization expression is lifted into constructors.
If you do this:
public TDValue type = new TDValue();
then regardless of which constructor is called that field will have an instance reference to a new TDValue object.
Note that the above is valid for classes, not for structs. For structs you need to ensure you assign all fields because memory is not always "allocated", it might be just reserved on the stack.

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

C# - how can a constructor be created that takes variables before they are declared?

Based on my question - take the following code:
class Nevermore60Customer: GenericCustomer
{
public Nevermore60Customer(string name, string referrerName)
: base (name)
{
this.referrerName = referrerName;
}
private string referrerName;
private uint highCostMinutesUsed;
To me, it appears the variable "referrrerName" is being initialized "after" it is being referenced as a passed parameter in the constructor.
public Nevermore60Customer(string name, string referrerName)
Am I worng, and if so how? Or if I am right and it is being initialized after it is being referenced in the constructor, how is it possible?
Thanks
The position of the variable declaration compared with the constructor is irrelevant to C#.
It would make this easier to discuss if you had different names for the parameter and field though:
class Test
{
public Test(string parameter)
{
this.field = parameter;
}
private string field;
}
Basically the field "exists" before the constructor is called. If the field is declared with an initializer, like this:
private string field = "default value";
then that initializer is run before the constructor, even though it may come after it within the source code.
The constructor argument is not an alias for the field. It hides the field name, this code won't work:
public Nevermore60Customer(string name, string referrerName) : base (name)
{
referrerName = referrerName; // bad
}
By using the "this." prefix, you can tell the compiler to assign the argument value to the field. It is a very common pattern, avoids having to come up with another name for the argument. Or do something awkward like prefixing the field name with, say, an underscore.
Not sure I understand the question. Your constructor has a strign parameter, referrerName, that you are assigning TO a private class variable, also called referrerName. I don't see where this.referrerName is referenced before its initialization?
this.referrerName refers to the class member declared as private string referrerName;
The referrerName to the right of the = is the parameter to the constructor.
It doesn't matter how you order the private members of the class and the constructor, the private members will always be initialized first.
C# is an object oriented language and you seem to confuse plain C procedural language concepts with C#. Unlike C, in C# the order of declaration does not matter as long as the instance is initialized before accessing and is within the scope.

Categories