Trying to understand static constructors - c#

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.

Related

Fail to initiate static variables in c# of Unity

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

What is the real difference between a static member and a constant in C#?

I'm learning C#,and now i'm trying to understand static members and constants.Which is the best way to declare a constant?
This way?
class Myclass
{
public const double G=9.8;
}
Or
class Myclass
{
private static double G{get;set;}
static MyClass()
{
G=9.8;
}
}
I've asked this question because,with the 2 ways i access the membre with the same code:
Console.WriteLine(Myclass.G);
constant:
Constant fields are defined at the time of declaration in the code
snippet, because once they are defined they can't be modified. By
default a constant is static, so you can't define them static from
your side.
It is also mandatory to assign a value to them at the time of
declaration otherwise it will give an error during compilation of the
program snippet. That's why it is also called a compile-time constant.
Explanation:
Consider ff. code:
void Sum(int j)
{
const int i = 9, k = 2;
const int A = i + k;
}
This will produce a result of 11, without showing any error since we already declared it at the initial point of declaration.
But how about:
void Sum(int j)
{
const int i = 9, k = 2;
//const int A = i + k;
Const int B = i + j;
}
This code snippet will take you toward a compile-time error, because there is no initialization, since it's evaluated at run time.
Points to Remember
Compile-time constant
Can't be declared static
Can't be modified or changed
Can be of any type of Access Modifier
Local scope
Needs to get initialized
Declared at the time of declaration
Static
The static keyword is used to declare a static member. If we are
declare a class as a static class then in this case all the class
members must be static too. The static keyword can be used effectively
with classes, fields, operators, events, methods and so on
effectively.
Consider ff. code:
class ReadOnly
{
static int i = 11;
public static void disp()
{
Console.WriteLine(i);
}
}
Explanation:
This code will show no error and produce a result (11), since we declared its value to be static at the time of declaration. So we can access it depending on our use in the program.
But how about this:
class ReadOnly
{
int i = 9;
public static void disp()
{
Console.WriteLine(i);
}
}
This snippet above will show an error, because we didn't declare a value for the static and we are trying to access it within a method. We can't do that.
Points to Remember:
Can't be used with indexers
Works with constructors too
By default it is private
Can be parameterized or public too
If its applied to a class then all the class members need to be static
You can read more about above explanation here: constant vs readonly vs static
Additional note for static methods.
Consider ff. code:
public class SomeClass {
public string SomeMethod() {
return "Hello, World.";
}
}
When you want to Access SomeMethod of SomeClass, you need to instantiate SomeClass first:
var some = new SomeClass();
string result = some.SomeClass(); //this will set result as "Hello, World."
Compared to a static method:
public class SomeClass {
public static string SomeMethod() {
return "Hello, World.";
}
}
When accessing SomeMethod, you don't need to instantiate SomeClass. You can access it directly by:
string result = SomeClass.SomeMethod(); //this will give "Hello, World."
Which is the best way to declare a constant?
Its not the best, its the only way: const double G = 9.8;.
Or (...) static double G { get; set; }
Thats not a constant! Constant means constant: 1 is a constant, 'c'is a constant, PI is a constant... they represent values that don't change, ever!. Your second implementation of G can change, therefore its not a constant.
Also, its important you notice that constants are known at compile time, there is no evaluation needed at runtime.
This is the reason why any reference type const (expect string which has specific compiler support through string literals) can only be initialized to null, any other option would need to be evaluated at runtime.
Its also the reason why only a finite set of value types can be declared as const too. All of them are existing types in the framework and.. surprise, surprise, they all have compiler literal constant support: 1, 'c', 9.8 or 0.25M but not 01/01/2017 (how else would the compiler know the values before runtime?).
Another interesting question you didn't make is: what about static readonly?
You can think of static readonly as "the poor man's" const. Its often used to circumvent the limitations const offers concerning what types and initializing values are allowed.
It is almost the same as a constant, but there are a few important and decisive differences:
It can change; although it is readonly, you can change it's value inside the static constructor of the declaring type. const can never change after initialized.
It is evaluated at runtime, not compile time as a true const.
Any type can be declared as a static readonly and initialized to any valid value as you would do with any regular field.
As a nittpicking side note, you shouldn't make G a constant ;). It changes, and quite a bit. G in Ecuador is different from G in the North Pole.
const variables are assigned values at time of definition.
They are available at compile time. You can even use a compile time evaluate-able expression at compile time. But once a value has been assigned to a const variable, it cannot be changed at any other time.
Using static field means the value will remain same for every user of the application, but this value can be changed by code in any of the classes, and it will change for every user of the application.
Do not use static for constants, use const only. const are by default static, and you cannot use static keyword with it.
Check this
void Main()
{
// You will not be able to change value for const variable.
Console.WriteLine(Myclass.G);
// You will be able to change value for static variable,
// and this change will impact all users of the application.
// For every user, this field will store value of 10 now.
// That will not be required or desired code behavior.
Myclass1.G = 10;
Console.WriteLine(Myclass1.G);
}
// Normal class with const field
class Myclass
{
public const double G=9.8;
}
//static class with static constructor
static class Myclass1
{
public static double G{get;set;}
static Myclass1()
{
G=9.8;
}
}
Read More
Here you are talking about two different things, and this is their definition from MSDN:
1- static modifier: To declare a static member, which belongs to the type itself rather than to a specific object. The static modifier can be used with classes, fields, methods, properties, operators, events, and constructors, but it cannot be used with indexers, finalizers, or types other than classes.
2- const keyword: To declare a constant field or a constant local. Constant fields and locals aren't variables and may not be modified. Constants can be numbers, Boolean values, strings, or a null reference. Don’t create a constant to represent information that you expect to change at any time.
So a static member is defined for a Class (for all its instances, and that's why you can access it directly from the name of the Class) but can be modified. a const field of class can not be modified.

'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.

Achieving Local Runtime Immutability in C#

I currently know of two ways to make an instance immutable in C#:
Method 1 - Compile Time Immutability
void Foo()
{
// Will be serialized as metadata and inserted
// as a literal. Only valid for compile-time constants
const int bar = 100;
}
Method 2 - Readonly Fields
class Baz
{
private readonly string frob;
public Baz()
{
// Can be set once in the constructor
// Only valid on members, not local variables
frob = "frob";
}
}
It would be nice to have a guarantee that, some instance, once instantiated, will not be changed. const and readonly do this to a small degree, but are limited in their scope. I can only use const for compile-time constants, and readonly for member variables.
Is there any way to give a local variable immutability after its initial instantiation (the way readonly works, but on a more general level)?
Scala does this with the var keyword, which declares a new immutable value, which cannot be reassigned to after it gets its initial value:
var xs = List(1,2,3,4,5) // xs is a value - cannot be reassigned to
xs = List(1,2,3,4,5,6); // will not compile
You can't prevent variables from being re-assigned in C# with the exception of fields, by as you have already mentioned using const or readonly.
You could make your own immutable version of any existing mutable type by wrapping it or if it's your own class, re-write it to be immutable but you can't achieve it for variables in a method which is what your question seems to be getting at.
F# has a few options for immutability (the 'let keyword if I'm remembering correctly) that C# doesn't so it might be worth looking at F# if you still want to leverage the power of .NET but with complete immutability.
If the wrapper is static it cannot be overwritten. This does sacrafice compile time checking on variable names and type safety.
public static class ReadOnly
{
private static readonly Dictionary<string, object> values = new Dictionary<string, object>();
public static bool SetValue(string name, object data)
{
if (values.ContainsKey(name))
return false;
values[name] = data;
return true;
}
public static object GetValue(string name)
{
return values[name];
}
}
ReadOnly.SetValue("xs", 1);
ReadOnly.SetValue("xs", 1); // will crash

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