Fail to initiate static variables in c# of Unity - c#

I was trying to make a singleton in Unity 2017.
public class Singleton {
public static readonly Singleton instance = new Singleton();
static readonly float FLOAT_VAL = 3.5f;
static readonly int INT_VAL = 3;
private Singleton() {
Debug.Log("FLOAT_VAL = " + FLOAT_VAL);
Debug.Log("INT_VAL = " + INT_VAL);
}
}
I expected to see the output of "FLOAT_VAL = 3.5" and "INT_VAL = 3". However, it came out with the output of "FLOAT_VAL = 0" and "INT_VAL = 0". Then I deleted both "readonly" modifiers, leaving "static" and still got two zero.
What happened to the initiation or construction of this singleton? How can I correctly give the values to the static variables? Is there anything to do with Unity? (I chose il2cpp when building the project, but this was tested under Editor Mode)
By the way, I figured out that the initiation of the variable "instance" didn't start until the first call (I used to think that all static vars get initialized when the assembly is loaded.). Is it also another Unity feature or just normal?

The fields get initialized in the order they are declared.... so since your instance comes first, your other values are zero. If you move them above your instance they will have the values you expect

From the C# language specification
§10.5.5.1
Static field initialization
The static field variable initializers of a class correspond to a
sequence of assignments that are executed in the textual order in
which they appear in the class declaration. If a static constructor
(§10.12) exists in the class, execution of the static field
initializers occurs immediately prior to executing that static
constructor.Otherwise, the static field initializers are executed at
an implementation-dependent time prior to the first use of a static
field of that class.
So basically, because you wrote instance first, it is initialised before FLOAT_VAL and INT_VAL. Reverse the order and you will see your expected results:
public class Singleton {
static readonly float FLOAT_VAL = 3.5f;
static readonly int INT_VAL = 3;
public static readonly Singleton instance = new Singleton();
private Singleton() {
Console.WriteLine("FLOAT_VAL = " + FLOAT_VAL);
Console.WriteLine("INT_VAL = " + INT_VAL);
}
}

If your class contains static fields, provide a static constructor that initializes them when the class is loaded.[MSDN]
Add a static constructor to initialize your static variables

Related

Clarifying Understanding of Fields

I'm currently learning C# in Unity through a series of video tutorials and just had fields introduced. Am I correct in saying that fields are just variables declared in the class level?
Yes, you can say this.
The main difference is that variables in methods (also called local variables) have a temporary value used during the method call. The next time you call the method the previous value of the variables are lost and you have to initialize them again. (I am not talking about advanced stuff like iterators and captured variables.)
On the other side, variables in classes and structs, i.e. fields, are living as long as the object lives. I.e., they keep their value between method calls.
Unlike local variables that are first undefined, fields are assigned a default value when an object is created from a class. Struct fields behave differently depending whether the struct is used as class field or variable. The struct fields have thee same definedness as the field or variable defining them.
As #elgonzo commented, there are two types of fields
Static fields. They are declared with the static modifier. Static fields exist exactly once for a specific class or struct, independently of the number of objects of this type.
Instance fields exist once per object (i.e. class or struct instance).
Private instance fields can only be accessed by instance methods and constructors of this class or struct, where as private static fields can be accessed by static and instance methods and constructors. (Methods include getters and setters of properties and indexers.)
Example. With this class...
public class A
{
private static int _staticCounter;
private int _instanceCounter;
public void Count()
{
_staticCounter++;
_instanceCounter++;
}
public void PrintCount()
{
Console.WriteLine($"Static = {_staticCounter}, Instance = {_instanceCounter}");
}
public static void PrintStatic()
{
Console.WriteLine($"Static = {_staticCounter}"); // Can only access static fields.
}
}
...this test...
A x = new A();
A y = new A();
x.Count();
x.Count();
y.Count();
y.Count();
y.Count();
x.PrintCount();
y.PrintCount();
A.PrintStatic();
Console.ReadKey();
...prints this to the console
Static = 5, Instance = 2
Static = 5, Instance = 3
Static = 5

Trying to understand static constructors

I am trying to understand need for static constructors. None of information I found answered following question I have. Why would you do this
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}
as opposed to this
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline = DateTime.Now.Ticks;
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
//static SimpleClass()
//{
//}
}
?
This is not dupe of other question, this is about static constructors which don't accept parameters.
The need is somehow obvious: You want to do more than some field initialization for your static members.
Logically if you have this class:
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline = DateTime.Now.Ticks;
}
You can re-write it to have the same effect:
class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;
static SimpleClass () {
baseline = DateTime.Now.Ticks;
}
}
But instead, you could do more in your static constructor such as inspecting (using reflection) some properties and emiting some fast accessors / getters to them, or just simple notify other systems that your type has been created, etc.
From Jeffrey Richter CLR via C# book:
When the C# compiler sees a class with static fields that use inline
initialization (the BeforeFieldInit class), the compiler emits the
class’s type definition table entry with the BeforeFieldInit metadata
flag. When the C# compiler sees a class with an explicit type
constructor (the Precise class), the compiler emits the class’s type
definition table entry without the BeforeFieldInit metadata flag. The
rationale behind this is as follows: initialization of static fields
needs to be done before the fields are accessed, whereas an explicit
type constructor can contain arbitrary code that can have observable
side effects; this code may need to run at a precise time.
Obviouselly there is something more than this happening behind the scenes, I would suggest you to read entire chapter from CLR via C#: "Type Constructors"
This is an example of a possible difference:
class SimpleClass
{
static readonly long A = DateTime.Now.Ticks;
static readonly long B = DateTime.Now.Ticks;
static SimpleClass()
{
}
}
A and B are not guaranteed to be the same value, though if you were to write it in the constructor, you could guarantee it:
class SimpleClass
{
static readonly long A;
static readonly long B;
static SimpleClass()
{
var ticks = DateTime.Now.Ticks;
A = ticks;
B = ticks;
}
}
In addition, order matters for instantiation of static members.
According to ECMA-334 regarding static field initialization:
The static field variable initializers of a class declaration
correspond to a sequence of assignments that are executed in the
textual order in which they appear in the class declaration. If a
static constructor (§17.11) exists in the class, execution of the
static field initializers occurs immediately prior to executing that
static constructor. Otherwise, the static field initializers are
executed at an implementation-dependent time prior to the first use of
a static field of that class
So, we can write something like this:
class SimpleClass
{
public static readonly long A = IdentityHelper.GetNext();
public static readonly long B = IdentityHelper.GetNext();
static SimpleClass()
{
}
}
public static class IdentityHelper
{
public static int previousIdentity = 0;
public static int GetNext()
{
return ++previousIdentity;
}
}
Here, A is guaranteed to be assigned before B. In this example, A will be 1, and B will be 2. We can guarantee that A < B (assuming the identity does not overflow and there's no issues with threading). Now, if we re-order the fields:
public static readonly long B = IdentityHelper.GetNext();
public static readonly long A = IdentityHelper.GetNext();
The functionality changes. Thus, we've created a side-effect which is not immediately clear simply by re-ordering the fields definitions.
A more likely scenario is, we may want to do this:
class SimpleClass
{
public static readonly long A = IdentityHelper.GetExpensiveResult().A;
public static readonly long B = IdentityHelper.GetExpensiveResult().B;
static SimpleClass()
{
}
}
Here, we're unable to share GetExpensiveResult() between the fields.

'private static readonly' fields and static/nonstatic constructors

I have three objects :
private static readonly Apple a, c;
private readonly Orange b;
This code is called from my constructor :
public SomeClass()
{
a = new Apple();
b = new Orange(a.getDna());
c = new Apple(b.getDna());
}
It gives me the error Readonly field cannot be used as an assignment target. If I remove either the static or readonly modifiers, it compiles perfectly. (Is there a wrong warning here?)
On checking other answers here on SO, I found that I should use a static constructor like :
static SomeClass()
{
a = new Apple();
c = new Apple(b.getDna());
}
public SomeClass()
{
b = new Orange(a.getDna());
}
But this would cause the static constructor to be called first and cause an error since b would not be initialized.
How do I circumvent this?
P.S. I'm relatively new to C#
Let's start by defining what is static and what's the difference between static and instance members.
A static member is a member that doesn't need an instance to exist: it "belongs to the class", and not to an object (a instance of the class).
Now the readonly modifier, says that a member can only be assigned a value in the constructor (or in its declaration, but that's not relevant here).
There are two types of constructors: static constructors and instance constructors... the difference is the same difference as above, and the readonly modifier is of course, applied to each type of constructor: static readonly would mean "you can only change its value in the static constructor", and instance readonly would mean "you can change its value in the instance constructor".
The static constructor is called the first time the type is accessed, so it's always called first.
Now, in the examples you are just randomly changing members to static or not just to try if it compiles.
Think about it for a second... in the static context you have no instance at all, so it's just not possible to access instance members on the static constructors... furthermore, by the time the static constructor is called, there's no way you could have any initialized instance, even externally defined, since it'll always be called before you have the chance to initialize one.
So this line within the static constructor makes no sense:
c = new Apple(b.getDna());
You are trying to access b, which is an instance member, but you are not saying which instance should you get the value from.
You should really rethink your design, and think why members would be static or not, not just "move things around and try to make it compile and run".
The error is correct because if you create another instance of SomeClass the static field a will be assigned twice, against the readonly constraint.
You are trying to assign values to read only static variables inside a instance constructor. At the point you call the instance constructor that variables are already assigned a value, which is null.
public SomeClass()
{
a = new Apple(); // it is already assigned as null.
b = new Orange(a.getDna()); //there is no value assigned to it yet
c = new Apple(b.getDna()); //it is already assigned as null
}
This happens because the static constructor is called before the instance constructor. You can have more details here:
A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
But then, you have the problem when you are trying to access an instance variable inside the static constructor. At that point, the instance constructor is not yet called, which means your variable b is not yet initialized.
You are facing a very common problem, where you are trying to mix instance variables and static variables. This approach can lead to very strange behaviours, like the one you are facing.
I suggest to you to don't mix this variables, make them all static or or make them all instance, but don't mix it. Otherwise, you might face different problems in the near future
The error message is in fact correct.
First, static means it belongs to the class. Non static means it is per instance. An instance method can modify a static variable, but a static method cannot modify an instance variable (which instance would it modify?)
Given that, readonly means you can only initialize during creation (e.g. constructor.)
You are getting the error because you are trying to assign a readonly static AFTER its creation in an instance constructor.
Is there a wrong warning here?
No. The warning is correct. If a field is readonly, we can assign it a value in two places: upon declaration or in the constructor. Further, if something is static, its associated constructor is static too. So, we can assign to a static and readonly field in two places:
Upon declaration or
in the static constructor.
We cannot do it in an instance constructor.
Your other question is about the inability of a static field to depend on an instance one.
How do I circumvent this?
Here is a creative way to circumvent it:
In the static constructor, assign to static _b.
In the instance constructor, assign the static _b to the instance's b.
We can even assign _b = null when we're done with it and still access the value that we earlier assigned to b.
Here is an example:
public class SomeClass
{
private static readonly Apple a, c;
private static Orange _b;
private readonly Orange b;
static SomeClass()
{
a = new Apple();
_b = new Orange(a.getDna());
c = new Apple(_b.getDna());
}
public SomeClass()
{
b = _b;
_b = null;
}
//
// the rest is just class definitions
//
public class Apple
{
public Apple(object o = null) {}
public object getDna() { return new object(); }
}
public class Orange
{
public Orange(object o = null) { }
public object getDna() { return new object(); }
}
}
It does let you circumvent the problem.

Understanding C# field initialization requirements

Considering the following code:
public class Progressor
{
private IProgress<int> progress = new Progress<int>(OnProgress);
private void OnProgress(int value)
{
//whatever
}
}
This gives the following error on compilation:
A field initializer cannot reference the non-static field, method, or property 'Progressor.OnProgress(int)'
I understand the restriction it is complaining about, but I don't understand why it is an issue, but the field can be initialized in the constructor instead as follows:
public class Progressor
{
private IProgress<int> progress;
public Progressor()
{
progress = new Progress<int>(OnProgress);
}
private void OnProgress(int value)
{
//whatever
}
}
What is the difference in C# regarding the field initialization vs constructor initialization that requires this restriction?
Field initialization come before base class constructor call, so it is not a valid object. Any method call with this as argument at this point leads to unverifiable code and throws a VerificationException if unverifiable code is not allowed. For example: in security transparent code.
10.11.2 Instance variable initializers
When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable-initializers of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration.
10.11.3 Constructor execution
Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.
Everything in my answer is just my thoughts on 'why it would be dangerous to allow that kind of access'. I don't know if that's the real reason why it was restricted.
C# spec says, that field initialization happens in the order fields are declared in the class:
10.5.5.2. Instance field initialization
The variable initializers are executed in the textual order in which
they appear in the class declaration.
Now, let's say the code you've mentioned is possible - you can call instance method from field initialization. It would make following code possible:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string GetMyString()
{
return "this is really important string";
}
}
So far so good. But let's abuse that power a little bit:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
_third = "not hey!";
return "this is really important string";
}
}
So, _second get's initialized before _third. GetMyString runs, _third get's "not hey!" value assigned, but later on it's own field initialization runs, and it's being set to `"hey!". Not really useful nor readable, right?
You could also use _third within GetMyString method:
public class Progressor
{
private string _first = "something";
private string _second = GetMyString();
private string _third = "hey!";
private string GetMyString()
{
return _third.Substring(0, 1);
}
}
What would you expect to be value of _second? Well, before field initialization runs all the fields get default values. For string it would be null, so you'll get unexpected NullReferenceException.
So imo, designers decided it's just easier to prevent people from making that kind of mistakes at all.
You could say, OK let's disallow accessing properties and calling methods, but let's allow using fields that were declared above the one you want to access it from. Something like:
public class Progressor
{
private string _first = "something";
private string _second = _first.ToUpperInvariant();
}
but not
public class Progressor
{
private string _first = "something";
private string _second = _third.ToUpperInvariant();
private string _third = "another";
}
That's seems useful and safe. But there is still a way to abuse it!
public class Progressor
{
private Lazy<string> _first = new Lazy<string>(GetMyString);
private string _second = _first.Value;
private string GetMyString()
{
// pick one from above examples
}
}
And all the problems with methods happen to come back again.
Section 10.5.5.2: Instance field initialization describes this behavior:
A variable initializer for an instance field cannot reference the
instance being created. Thus, it is a compile-time error to reference
this in a variable initializer, as it is a compile-time error for a
variable initializer to reference any instance member through a
simple-name
This behavior applies to your code because OnProgress is an implicit reference to the instance being created.
The answer is more or less, the designers of C# preferred it that way.
Since all field initializers are translated into instructions in the constructor(s) which go before any other statements in the constructor, there is no technical reason why this should not be possible. So it is a design choice.
The good thing about a constructor is that it makes it clear in what order the assignments are done.
Note that with static members, the C# designers chose differently. For example:
static int a = 10;
static int b = a;
is allowed, and different from this (also allowed):
static int b = a;
static int a = 10;
which can be confusing.
If you make:
partial class C
{
static int b = a;
}
and elsewhere (in other file):
partial class C
{
static int a = 10;
}
I do not even think it is well-defined what will happen.
Of course for your particular example with delegates in an instance field initializer:
Action<int> progress = OnProgress; // ILLEGAL (non-static method OnProgress)
there is really no problem since it is not a read or an invocation of the non-static member. Rather the method info is used, and it does not depend on any initialization. But according to the C# Language Specification it is still a compile-time error.

Does C# resolve dependencies among static data members automatically?

If one static data member depends on another static data member, does C#/.NET guarantee the depended static member is initialized before the dependent member?
For example, we have one class like:
class Foo
{
public static string a = "abc";
public static string b = Foo.a + "def";
}
When Foo.b is accessed, is it always "abcdef" or can be "def"?
If this is not guaranteed, is there any better way to make sure depended member initialized first?
Like said before, static field initialization is deterministic and goes according to the textual declaration ordering.
Take this, for example:
class Foo
{
public static string b = a + "def";
public static string a = "abc";
}
Foo.b will always result in "def".
For that matter, when there is a dependency between static fields, it is better to use a static initializer :
class Foo
{
public static string b;
public static string a;
static Foo()
{
a = "abc";
b = a + "def";
}
}
That way, you explicitly express your concern about the initialization order; or dependency for that matter (even if the compiler won't help if you accidentally swap the initialization statements.) The above will have the expected values stored in a and b (respectively "abc" and "abcdef").
However, things might get twisty (and implementation specific) for the initialization of static fields defined in multiple classes. The section 10.4.5.1 Static field initialization of the language specification talks about it some more.
It will show allways "abcdef", because initialization goes top down in source, today just like before.
All static members will be initialized upon loading of the classtype holding them.

Categories

Resources