What is Static?
In common run throughs, static means fixed or not changing unless someone changes it. Similarly, in computer programming languages, a static variable is a variable that has been allocated "statically", meaning that value assigned to a static variable remains same throughout the entire run of the program.
Let us understand the concept of static in a simpler way using the below use case: Your brother or sister is studying in class V and there can be a maximum of 30 total students enrolled in his/her classroom.
Consider that the teacher makes a note of the weight and height of each of the student. I ask you one question, does the weight of each one of them have the same value? The answer is No. Each one of them has different values for weight.
Consider if one student consumes more food and puts on weight. Will it affect the value of the weight of all the students? The answer is No. Each one of them has different values for weight.
So, the weight of the student is a non- static variable. Each student has its own value for that.
Let's say, at the beginning of the session, 30 students sign up in your sister or brother’s class. I ask you one question; how many students can be enrolled in the classroom? You will tell me 30. I ask the same question to another student. All will say 30.
After a few months one classmate doesn't like your school and s/he discontinues ... Drops out:)..!!! . I ask the same question; how many students can be enrolled in classroom? You will tell me 30. I ask the same question to another student. All will say 30.
So the maximum number of students that can be enrolled in the class is a static variable that will remain the same throughout the entire run of the program until unless the school administration makes any change to the value.
Static in C#
C# programs includes "static" keywords just like other programming languages such as C++, Java, etc. The Static keyword can be applied on classes, variables, methods, properties, operators, events and constructors. However, it cannot be used with indexers, destructors or types other than classes.
Prefixing the static modifier before classes, variables, methods, properties, operators, events and constructors makes them static, meaning the value assigned to it will remain the same throughout the entire run of the program and can be accessed from anywhere in the program without any object reference provided it has been declared as public.
Static Member Variables
The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name. Only one copy of a static member exists, regardless of how many instances of the class are created.
Scope
In terms of scope and extent, static member variables have the entire run of the program, but may have more limited scope.
Local Variable
Declaring a private static variable in a class makes it non-accessible from another class but it can be accessed from within the class; for example to store the count of instances we can declare a private static variable and public instance property return count of instances.
- publicclassStaticVariableClass {
-
-
-
-
- public StaticVariableClass() {
- _numberOfInstances = ++_numberOfInstances;
- }
-
-
-
-
-
- privatestaticint _numberOfInstances = 0;
-
-
-
-
- publicint NumberOfInstances {
- get {
- return _numberOfInstances;
- }
- }
- }
- Static variable will not be accessible using StaticVariableClass._numberOfInstances directly but will be accessible after creating an object of the class StaticVariableClass.
- classProgram {
- staticvoid Main(string[] args) {
- StaticVariableClass staticVariableClassObject = newStaticVariableClass();
- Console.WriteLine(staticVariableClassObject.NumberOfInstances);
- Console.ReadLine();
- }
- }
As we can see the default constructor increments the value of static variable _numberOfInstances whenever class is instantiated using the new keyword. Output of this program will return 1.
Global Variable
Please note that C# is an object-oriented programming (OOP) language and does not support global variables directly. The solution is to add a static class and declare a public static variable or declare a public static variable in a class makes it accessible from anywhere in the program meaning a global variable. Using a global variable violates the OOP concept a bit, but can be very useful in certain circumstances, for example to store the maximum number of students that can be enrolled in class we can declare a static global variable.
- publicstaticclassStaticGlobalVariable {
-
-
-
-
-
-
- privatestaticint _maximumNumberOfStudents = 30;
-
-
-
-
- publicstaticint MaximumNumberOfStudents {
- get {
- return _maximumNumberOfStudents;
- }
- }
- }
- classProgram {
- staticvoid Main(string[] args) {
- Console.WriteLine("maximum students that can be enrolled in a class - {0}", StaticGlobalVariable.MaximumNumberOfStudents);
- Console.ReadLine();
- }
- }
Accessibility/Compatibility
Non Static methods and properties can access both static and instance (non-static) fields and events.
-
-
-
-
- publicclassNonStaticMethodAccessStaticMember {
-
-
-
-
-
- privatestaticint _numberOfInstances = 0;
-
-
-
-
-
- publicvoid PrintNumberOfInstances() {
- Console.WriteLine("Number of Instances: {0}", _numberOfInstances);
- }
- }
Static methods and properties cannot access non-static fields and events. Otherwise it gives a compilation error - CS0120 An object reference is required for the non-static field, method, or property
-
-
-
-
- publicclassStaticMethodAccessNonStaticMember {
-
-
-
-
-
- privateint _numberOfInstances = 0;
-
-
-
-
- publicstaticvoid StaticPrintNumberOfInstances() {
- Console.WriteLine("Number of Instances: {0}", _numberOfInstances);
- }
- }
On Compilation the above code gives the below error:
- Static methods and properties cannot access an instance variable of any object
- Static methods and properties can access instance variable of any object if passed in a method parameter explicitly.
- publicclassRegistration {
- privateStudent _selectedStudent = null;
- privateCourse _selectedCourse = null;
-
-
-
- privatereadonlyList < Student > _students = newList < Student > () {
- newStudent() {
- StudentId = 1, FirstName = "Hemant", LastName = "Jindal"
- },
- newStudent() {
- StudentId = 2, FirstName = "Titiksha", LastName = "Jindal"
- }
- };
-
-
-
- privatereadonlyList < Course > _courses = newList < Course > () {
- newCourse() {
- CourseId = 1, CourseName = "Computer Programming"
- },
- newCourse() {
- CourseId = 2, CourseName = "Artifical Intelligence"
- },
- };
-
-
-
-
-
-
- publicvoid Register(int studentId, int courseId) {
-
- _selectedStudent = _students.FirstOrDefault(x => x.StudentId == studentId);
-
- _selectedCourse = _courses.FirstOrDefault((c => c.CourseId == courseId));
- StudentCourseEnrollment.Enroll(_selectedStudent, _selectedCourse);
- }
- }
-
-
-
-
-
- publicclassStudentCourseEnrollment {
- publicstaticvoid Enroll(Student student, Course course) {
- Console.WriteLine("{0} is enrolled to the course {1}", student.FirstName, course.CourseName);
- }
- }
Access Modifiers
- Static members in non-static class can be marked as public, protected, internal. It is always recommended to use public because static members cannot be accessed using instance
- Static members in non-static and static class cannot be overridden meaning cannot be marked as Virtual, Abstract, or override. Doing so gives a compilation error - CS0112 A static member cannot be marked as override, virtual, or abstract
- publicclassBaseClass {
-
-
-
- publicstaticvirtualvoid StaticMethod() {}
- }
-
-
-
- publicclassDerivedClass: BaseClass {
-
-
-
- publicoverridevoid StaticMethod() {}
- }
- Static methods in class can be overloaded.
- publicclassOverloadedStaticMethods {
- publicstaticint AddNumbers(int number1, int number2) {
- Console.WriteLine("Method with two parameters");
- return number1 + number2;
- }
- publicstaticint AddNumbers(int number1, int number2, int number3) {
- Console.WriteLine("Method with three parameters");
- return number1 + number2 + number3;
- }
- }
Static Class
A static class is basically the same as a non-static class, except static class does not maintain any data, state and behavior which means that static class is stateless. A static class can be used as a convenient container for sets of methods that just operate on input parameters and do not have to get or set any internal instance fields. An example of static class can be a class to define Interest calculator, EMI calculator, Temperature Conversion, logging error/message and displaying a message on GUI.
- Static classes can have only static fields/members and static methods.
- Static classes are implicitly abstract (i.e. they're compiled to IL which describes an abstract class) but you can't add the abstract modifier yourself. Doing so gives a compilation error - CS0418 an abstract class cannot be sealed or static,
- publicabstractstaticclassAbstractStaticClass
- {
- }
- Static class object can neither be created nor instantiated. Doing so gives a compilation error - CS0712 Cannot create an instance of the static class and CS0723 Cannot declare a variable of static type
- classProgram {
- staticvoid Main(string[] args) {
-
-
-
- SampleClass sampleClassObject = newSampleClass();
- }
- }
- staticclassSampleClass {}
- Static classes always derives from object. They can be neither inherited nor derived meaning they cannot be a part of inheritance. Doing so gives a compilation error - CS0713. One possible reason is that .net CLR maintains only one copy of static members or class per application domain
- staticclassBaseClass {}
-
-
-
-
- staticclassDerivedClass: BaseClass {}
-
-
-
-
- classNonStaticDerivedClass: BaseClass {}
Static Constructor
- Static constructor is used to initialize static data members as soon as the class is referenced the first time.
- Static constructor can be defined within non-static class.
- Static constructor for a class executes at most one time during a single program instantiation
- publicclassDemoInitializeStaticDataMembers {
- privatestaticreadonlystring StaticVariable;
-
-
-
- static DemoInitializeStaticDataMembers() {
- StaticVariable = "My Name is StaticVariable and I am initialized only once";
- Console.WriteLine(StaticVariable);
- }
-
-
-
-
-
- privatestaticint _numberOfInstances = 0;
- public DemoInitializeStaticDataMembers() {
- _numberOfInstances = ++_numberOfInstances;
- Console.WriteLine("Instance Number: {0}", _numberOfInstances);
- }
- }
- staticvoid Main(string[] args) {
- DemoInitializeStaticDataMembers objectOne = newDemoInitializeStaticDataMembers();
- DemoInitializeStaticDataMembers objectTwo = newDemoInitializeStaticDataMembers();
-
- System.Console.WriteLine("Press any key to exit.");
- System.Console.ReadKey();
- }
Output
My Name is StaticVariable and I am initialized only once
"Instance Number: 1"
"Instance Number: 2"
- Static Constructor defined within the child class executes well before static constructor defined in the parent class but executes once. In the below example we have defined a class named “BaseClass” and another class named “DerivedClass” inheriting BaseClass. We have defined static constructor in both of these classes. Now we will see the output of these static constructors defined
- publicclassBaseClass {
-
-
-
- static BaseClass() {
- Console.WriteLine("Hi! I am static class constructor defined in BaseClass");
- }
- }
- publicclassDerivedClass: BaseClass {
-
-
-
- static DerivedClass() {
- Console.WriteLine("Hi! I am static class constructor defined in DerivedClass");
- }
- }
- staticvoid Main(string[] args) {
- BaseClass baseClassObject = newDerivedClass();
-
- System.Console.WriteLine("Press any key to exit.");
- System.Console.ReadKey();
- }
Output
"Hi! I am static class constructor defined in DerivedClass"
"Hi! I am static class constructor defined in BaseClass"
- Static Constructor executes instance constructor and only executes once. In the below example we have static constructor and instance constructor defined in the class. Now we will see the output of these static constructors and instance constructors defined.
- publicclassBaseClass {
-
-
-
- static BaseClass() {
- Console.WriteLine("Hi! I am static class constructor defined in BaseClass");
- }
- public BaseClass() {
- Console.WriteLine("Hi! I am Instance class constructor defined in BaseClass");
- }
- }
- staticvoid Main(string[] args) {
- BaseClass baseClassObject1 = newBaseClass();
- BaseClass baseClassObject2 = newBaseClass();
-
- System.Console.WriteLine("Press any key to exit.");
- System.Console.ReadKey();
- }
Output
"Hi! I am static class constructor defined in BaseClass"
"Hi! I am Instance class constructor defined in BaseClass"
"Hi! I am Instance class constructor defined in BaseClass"
- Static Constructor does not have access Modifiers. Doing so gives a compilation error - CS0515 access modifiers are not allowed on static constructors
- A class can have only one Static Constructor and that too is parameter-less. Doing otherwise gives a compilation error - CS0132: a static constructor must be parameterless
- publicclassStaticClassWithTwoConstructor {
-
-
-
- static StaticClassWithTwoConstructor() {}
-
-
-
-
- static StaticClassWithTwoConstructor(int counterValue) {}
- }
Memory Allocation
C# compiler allocates memory to a static type at compile time unlike instance types, meaning before the associated program is executed.
Scope of static variable is global, meaning these must be available throughout the entire run of the program and they should not be collected by Garbage Collector, these cannot be stored in the stack, as the stack frame will get popped up once the method execution is completed. To overcome this .Net run-time stores the static variables in a special region within the Heap, called High Frequency Heap, which is being used to store objects that are frequently accessed and should not be collected by garbage collector.
The static variable itself is not garbage collected - it is just a memory location that contains a reference to an object. Static fields are considered to be GC roots so any references to them will not be garbage collected as long as the field contains that reference. Note that Objects referenced by static variables will only be garbage collected when the relevant AppDomain is garbage collected or the field is changed to point to a new reference or the field value is set to null then the object whose reference was stored there becomes eligible for collection.
Also the garbage collector doesn't collect variables, it collects objects. Local and static variables are not part of any object so they are never collected by GC.