Static Constructor With Parameter - c#

I've read this thread "When is a static constructor called in C#" including the Programming Guide.
But is there any way to use a static constructor WITH a parameter?
I see the problem, that the static constructor is invoked bevor the first instance is created. I search for any smart solution/workaraound.
Here an example:
public class Bus
{
protected static readonly DateTime globalStartTime;
protected static readonly int FirstBusNumber;
protected int RouteNumber { get; set; }
static Bus(/*int firstBusNumber*/)//Error if uncomment: The static constructor must be parameterless
{
//FirstBusNumer = firstBusNumber;
globalStartTime = DateTime.Now;
Console.WriteLine($"The First Bus #{FirstBusNumber} starts at global start time {globalStartTime.ToLongTimeString()}");
}
public Bus(int routeNum)
{
RouteNumber = routeNum;
Console.WriteLine($"Bus #{RouteNumber} is created.");
}
public void Drive()
{
var elapsedTime = DateTime.Now - globalStartTime;
Console.WriteLine("{0} is starting its route {1:N2} minutes after the first Bus #{2}.",
RouteNumber,
elapsedTime.TotalMilliseconds,
FirstBusNumber
);
}
}
...
var bus1 = new Bus(71);
var bus2 = new Bus(72);
bus1.Drive();
System.Threading.Thread.Sleep(25);
bus2.Drive();
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
Notice:
Following code is not an acceptable solution.
public Bus(int routeNum)
{
if (FirstBusNumber < 1)
FirstBusNumber = routeNum;
// ...
}

As per MSDN,
A static constructor is called automatically to initialize the class
before the first instance is created. Therefore you can't send it any parameters.
But you can create a method static to init your static values.
Check fiddle https://dotnetfiddle.net/4fnahi
public class Program
{
public static void Main()
{
Bus.Init(0);
Bus bus1 = new Bus(71);
Console.WriteLine(Bus.FirstBusNumber); // it prints 71 as your expected
}
}
public class Bus
{
public static int FirstBusNumber;
public static void Init(int firstBusNumber) => FirstBusNumber = firstBusNumber;
public Bus(int routeNum)
{
if (FirstBusNumber < 1)
FirstBusNumber = routeNum;
}
}

Firstly your example is from Microsoft docs, you can read more [here]
You, can't create a static constructor in c#. If you want specific type behavior you opt to instance class. There is a workaround, you can create a static method that settings static members, but you will need remember to use it explicitly.
Static relate to type itself. Ensure that your static constructor set static globalStartTime for this type once, it initializes the class before the first instance is created
You should really rethink if you need a static construct with a parameter.

Related

C# Unity > Static instance member not causing constructor to be called

I have noticed a rather weird behaviour in my application I am creating;
I have a class I defined that has a static "instance" variable of the class type.
I would assume that (as per code attached) the constructor would be called.
Alas, it is not, unless I use the Void.get in a non-static field anywhere in my code.
public class Void : TilePrototype {
public static Tile get = new Tile((int)TileEntities.Void);
public static Void instance = new Void();
public Void() {
Debug.Log("created");
id = (int)TileEntities.Void;
isBlocking = true;
register();
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
So when I have something like :
public static TileStack empty = new TileStack(Void.get, Void.get);
the Void class constructor never gets called. But, if I have:
Tile t = Void.get;
Anywhere in my code it will be called.
Why?
Thanks.
This is a really really subtle and nuanced area of C#; basically, you've stumbled into "beforefieldinit" and the difference between a static constructor and a type initializer. You can reasonably ask "when does a static constructor run?", and MSDN will tell you:
It is called automatically before the first instance is created or any static members are referenced.
Except... public static TileStack empty = new TileStack(Void.get, Void.get); isn't a static constructor! It is a static field initializer. And that has different rules, which basically are "I'll run when I must, no later, possibly sooner". To illustrate with an example: the following will not (probably) run your code, because it doesn't have to - there isn't anything demanding the field:
class Program
{
static void Main()
{
GC.KeepAlive(new Foo());
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
However, if we make a tiny tweak:
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
static Foo() { } // <=== added this
}
Now it has a static constructor, so it must obey the "before the first instance is created" part, which means it needs to also run the static field initializers, and so on and so on.
Without this, the static field initializer can be deferred until something touches the static fields. If any of your code actually touches empty, then it will run the static field initializer, and the instance will be created. Meaning: this would also have this effect:
class Program
{
static void Main()
{
GC.KeepAlive(Foo.empty);
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
This ability to defer execution of the static initialization until the static fields are actually touched is called "beforefieldinit", and it is enabled if a type has a static field initializer but no static constructor. If "beforefieldinit" isn't enabled, then the "before the first instance is created or any static members are referenced" logic applies.
Thanks to Marc Gravell's aswer I came up with this contraption (and admittedly I do like the new solution more than the old one, so thanks again!)
Modifications done to the Void class:
public class Void : TilePrototype {
public static Void instance = new Void();
public static Tile get {
get {
return new Tile(instance.id);
}
}
public Void() {
isBlocking = true;
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
}
So as You can see I made the "get" variable a property, so that it's evaluated later, when you actually need the tile, not on construction.
I've changed all "get"s this way.
Second change is in the TilePrototype:
public class TilePrototype {
public static Dictionary<int, TilePrototype> tilePrototypeDictionary = new Dictionary<int, TilePrototype>();
public static void registerPrototype(int id, TilePrototype tp){
tp.id = id;
tilePrototypeDictionary.Add(id, tp);
}
public static bool registered = false;
public static void registerAll(){
if( registered ) return;
registerPrototype(0, Void.instance);
registerPrototype(1, Air.instance);
registerPrototype(2, Floor.instance);
registerPrototype(3, Wall.instance);
(...)
Here I've added the registerPrototype and registerAll functions.
This gives me easy access to all the registered type ids (by say Wall.instance.id) as well as the other way around (from id to instance via the Dictionary)
I also have all registered things in one place, with the possibility of runtime adding more
Overall, much neater, and here I assure that all tiles are registered properly and assigned proper IDs.
Change of ID is simple and in one place and everywhere else, access to this ID is done via a short .instance.id
Thanks again for the help :)

Init static field befor calling any static method in C# [duplicate]

This question already has answers here:
C# static class constructor
(7 answers)
What is the use of static constructors?
(8 answers)
Closed 5 years ago.
In my class there are several methods with the following signature:
public static void SomeMethod()
{
...
}
Most of these methods depend on the value of the private static field.
It is necessary that the caller had any way to assign a value to this field before calling any of these static methods.
I want to have a single Random object for use by all classes in the application. How do I pass a reference to this object to use it in the static methods of another class?
I have a private static field in the class with static methods and a static initializer:
public static void Init(Random random)
{
_random = random;
}
But how to make sure that the initializer was called? To do the check and throw exceptions in every method, it seems to me redundant. There may be another option.
Finally I found an acceptable solution for me:
Define public static property in the class that contains application entry point:public static Random Rnd { get; } = new Random();
Define private static Random _random in other classes;
Implement a static constructor for other classes that includes this code:
Type type = Assembly.GetExecutingAssembly().EntryPoint.DeclaringType;
var randomTypeProperties =
type.GetProperties().Where(p => p.PropertyType == typeof(Random));
foreach (var propertyInfo in randomTypeProperties)
{
_random = (Random)propertyInfo.GetValue(null);
}
I can mark a message from #Andy as the answer, because it is after all a static constructor.
Thank you to everyone who took part in the discussion.
It's never too late to learn. Yesterday, as I read about the design patterns, I realized that the Singlton is exactly what I needed:
public sealed class RandomAsSingleton : Random
{
private static volatile RandomAsSingleton _instance;
private static readonly object _syncRoot = new object();
private RandomAsSingleton() { }
public static RandomAsSingleton Instance
{
get
{
lock (_syncRoot)
{
if (ReferenceEquals(_instance, null)) { _instance = new RandomAsSingleton(); }
return _instance;
}
}
}
}
My previous solution seems to me a little bit ugly right now.
You might want to use a static constructor
// Static constructor is called at most one time, before any
// instance constructor is invoked or member is accessed.
static SimpleClass()
{
// set your private static field
}
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

sharing variable of c# within many classes

How should I design something like this? I have a projects that have many classes and I wish to have a counter (int type) that can be accessed by these classes. There should be only one instance of the variable and every time it will add one to the variable.
Use a static class with a public property would be the most simple solution. Depending on your situation, you need more advanced options (for multihreading, unittesting/mocking etc.)
You could use a singleton class to make testing a bit easier and locking in case of multithreading.
An example could be:
public class Counting
{
private readonly Object _thisLock = new Object();
private static readonly Lazy<Counting> InstanceField =
new Lazy<Counting>(() => new Counting());
public static Counting Instance // Singleton
{
get
{
return InstanceField.Value;
}
}
private int _counter;
public int Counter
{
get
{
return _counter;
}
set
{
lock (_thisLock) // Locking
{
_counter = value;
}
}
}
protected Counting()
{
}
}
And use it this way:
Counting.Instance.Counter ++;
You can create a utility static class with all static memebers.
static class Utility
{
public static int Count = 123;//some value
/*some other variables*/
}
class MyClass
{
int mycount = Utility.Count;
}
Note: if you want to access your utility class outside the assembly you need to make your class as public

Static code blocks

Going from Java to C# I have the following question:
In java I could do the following:
public class Application {
static int attribute;
static {
attribute = 5;
}
// ... rest of code
}
I know I can initialize this from the constructor but this does not fit my needs (I want to initialize and call some utility functions without create the object).
Does C# support this? If yes, how can I get this done?
Thanks in advance,
public class Application
{
static int attribute;
static Application()
{
attribute = 5;
} // removed
}
You can use the C# equivalent static constructors. Please don't confuse it with a regular constructor. A regular constructor doesn't have a static modifier in front of it.
I am assuming your //... rest of the code need to be also run once. If you don't have such code you can just simply do this.
public class Application
{
static int attribute = 5;
}
You just can write a static constructor block like this,
static Application(){
attribute=5;
}
This is what I could think of.
In your particular scenario, you could do the following:
public class Application {
static int attribute = 5;
// ... rest of code
}
UPDATE:
It sounds like you want to call a static method. You can do that as follows:
public static class Application {
static int attribute = 5;
public static int UtilityMethod(int x) {
return x + attribute;
}
}
I find something else useful. If your variable needs more than one expressions/statements to initialize, use this!
static A a = new Func<A>(() => {
// do it here
return new A();
})();
This approach is not limited on classes.
-A static constructor doesn't have any parameter.
-A static class can contain only one static constructor.
-A static constructor executes first when we run the program.
Example:
namespace InterviewPreparation
{
public static class Program
{ //static Class
static Program()
{ //Static constructor
Console.WriteLine("This is static consturctor.");
}
public static void Main()
{ //static main method
Console.WriteLine("This is main function.");
Console.ReadKey();
}
}
}
Output:
This is static constructor.
This is main function.

How statics are initialized in C#

Ok, I have greatly changed the code to show the actual problem more clearly. I have tested this code, and it definitely fails.
public class MyEnumBase
{
private int _val;
private static Dictionary<int, MyEnumBase> ValueMap = new Dictionary<int, MyEnumBase>();
protected MyEnumBase()
{
_val = ValueMap.Count;
ValueMap.Add(_val, this);
}
public static MyEnumBase ValueOf(int i)
{
return ValueMap[i];
}
public static IEnumerable<MyEnumBase> Values { get { return ValueMap.Values; } }
public override string ToString()
{
return string.Format("MyEnum({0})", _val);
}
}
public class Colors : MyEnumBase
{
public static readonly Colors Red = new Colors();
public static readonly Colors Green = new Colors();
public static readonly Colors Blue = new Colors();
public static readonly Colors Yellow = new Colors();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("color value of 1 is " + Colors.ValueOf(2));
}
}
The following code fails because the Colors constructor is never called before ValueOf() is called. Is there a clean way to ensure that all my static fields are called before I call ValueOf?
Thanks,
~S
Static fields get initialized before you use them. Exact time depends on implementation and you should not make any assumptions about it. Static fields 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
(Section 10.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.
The code that you posted should work:
Child.TimesConstructed()
will not print 0 if you access one of the children (Child.C1) prior to this call.

Categories