Saturday, November 04, 2006

Static Constructors


Static Constructors:
  1. Cannot have parameters
static A(int i) {} // error CS0132: 'A.A(int)': a static constructor must be parameterless
  1. Cannot have accessibility modifiers
public static A() {}; // error CS0515: 'A.A()': access modifiers are not allowed on static constructors

  • Cannot be called explicitly

  • Called when the class is loaded for the first time

  • Run at most once per application domain

  • Can be declared for a struct as well

  • Execution is triggered by when an instance of the class is created or any of the static members of the class are referenced.

  • For a type is run at most once per application domain.

  • That are marked extern usually specifies a DllImport attribute.  Note that the keyword here is usually.   The compiler doesn’t mandate you to specify one.  It merely generates a warning when the following is compiled into a library or application.

  • TestSC.cs(3,16): warning CS0626: Method, operator, or accessor 'A.A()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation.  

public class A
{
     extern static A();
     static int i =2;
     public static void Main() { return; }

}

Upon execution of the application it throws a TypeLoadException:
Unhandled Exception: System.TypeLoadException: Could not load type 'A' from assembly 'TestSC, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' because the method '.cctor' has no implementation (no RVA).
  1. When present in a class force the compiler to omit beforefieldinit declaration.  The following text discusses ramifications.

Verbatim from C# Specification v.1.0: If a static constructor 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

Program #1
//Whether field i or j would be initialized first is implementation dependant.
class A
{
     static int i = 2;
}

class B
{
     static int j = 5;
}


On ILDASM

.class public auto ansi beforefieldinit A
       extends [mscorlib]System.Object
{
} // end of class A


Program #2
class Test
{
     public static void Main()
     {
          System.Console.WriteLine(“j = {0}, i={1}”,B.j,A.i);
     }
}
class A
{
     static int i = 2;
     static A() {};
}

class B
{
     static int j = 5;
     static B() {};
}

Since B.j is used first, field ‘j’ is guaranteed to get initialized first.

On ILDASM

.class public auto ansi A
       extends [mscorlib]System.Object
{
} // end of class A


     





Note that there’s no beforefieldinit in the declaration:

  1. Can have a return statement with no expression terminating it.

Usage:
  1. Can be used to assign computed static fields and static readonly fields

  2. To make sure that the type is not marked with beforefieldinit.


Explicit Interface Implementation

I was looking through my study notes when I came across several short programs I wrote sometimes ago that highlight important features of the C# language.  I’ll be posting the same in the coming posts with examples of when to use them.

//Explicit interface definition
//Be able to call an interface method ONLY through that interface

using System;

public class TestInterface : ITestInterface
{
     public void Method1()
     {
          Console.WriteLine("Method 1 Called");
     }     

     public void CallMethod1()
     {
          Method1();
     }
     public void CallMethod2()
     {
          ((ITestInterface)this).Method2();
          Method2();
     }


     ///ITestInterface implementation
     ///Two separate implementations of methods, both explicit and implicit
     

     //Explicit interface implementation
     void ITestInterface.Method2()
     {
          Console.WriteLine("Method 2 Called through ITestInterface");
     }

     //Implicit interface implementation
     public void Method2()
     {
          Console.WriteLine("Method 2 called through the class reference");
     }
}

public class InterfaceCaller
{
     public static void Main()
     {
          TestInterface ti = new TestInterface();
          ti.CallMethod1();
          ti.CallMethod2();
          ti.Method2(); //No such method compiler error if implicit interface implementation is omitted.
     }
}




public interface ITestInterface
{
     void Method1();
     void Method2();
}


Usage Scenarios:

  • Explicit Interface Implementation: Restrict the method access to be through the defined interface only.

  • While writing wrappers you want to restrict your team members to work only with the interface that you provide.  You may have earmarked the class for refactoring later.

  • Both EII & III: Provide two different implementations of the same method.

  • For me personally, this is dangerous.  Unless your specific situation demands that you employ this feature, it is better to leave this alone.