Working of static constructor in case of Generic Types

G

Guest

It seems the static constructor is supposed to be called, ONLY once for a
particular type. If that's the case, why does the following code throws an
exception?

using System;
using System.Collections.Generic;
using System.IO;

namespace GenericTypes
{
class Program
{
static void Main(string[] args)
{

MyList<int> lList;
try
{
lList = new MyList<int>();
}
catch
{
}
//Following line throws an error
//should the static constructor, be not called for this instance?
MyList<int> lList1 = new MyList<int>();
try
{
MyList<double> ldblList = new MyList<double>();
}
catch
{
}

}

class MyList<T>
{
static int i;
static List<T> _myList;
static MyList()
{
_myList = new List<T>();
System.Console.WriteLine("Called for " + typeof(T));
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum");
}

}

}
}
}
 
G

Guest

rvmaccount said:
It seems the static constructor is supposed to be called, ONLY once for a
particular type. If that's the case, why does the following code throws an
exception?

using System;
using System.Collections.Generic;
using System.IO;

namespace GenericTypes
{
class Program
{
static void Main(string[] args)
{

MyList<int> lList;
try
{
lList = new MyList<int>();
}
catch
{
}
//Following line throws an error
//should the static constructor, be not called for this instance?

The static constructor is not called for that instance. If you debug the
code you will see that the static constructor is only entered once.

As the static constructor threw an exception the class is unusable, and
the same exception will be rethrown for every attempt to create an
instance of the class.
 
C

Christof Nordiek

The first call of new MyList<int> also throws an exception, but that is
handled by the empty catch-block. Then the class MyList<int> is still not
constructed. So the static constructor is also triggered by the second
MyList<int>.
 
C

Christof Nordiek

The first call of new MyList<int> also throws an exception, but that is
handled by the empty catch-block. Then the class MyList<int> is still not
constructed. So the static constructor is also triggered by the second
MyList<int>.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

If you debug the code, you will see that the static constructor is only
executed once. Instead the same exception that the static constructor
threw is rethrown when trying to create another instance of the class.

Christof said:
The first call of new MyList<int> also throws an exception, but that is
handled by the empty catch-block. Then the class MyList<int> is still not
constructed. So the static constructor is also triggered by the second
MyList<int>.

rvmaccount said:
It seems the static constructor is supposed to be called, ONLY once for a
particular type. If that's the case, why does the following code throws an
exception?

using System;
using System.Collections.Generic;
using System.IO;

namespace GenericTypes
{
class Program
{
static void Main(string[] args)
{

MyList<int> lList;
try
{
lList = new MyList<int>();
}
catch
{
}
//Following line throws an error
//should the static constructor, be not called for this
instance?
MyList<int> lList1 = new MyList<int>();
try
{
MyList<double> ldblList = new MyList<double>();
}
catch
{
}

}

class MyList<T>
{
static int i;
static List<T> _myList;
static MyList()
{
_myList = new List<T>();
System.Console.WriteLine("Called for " + typeof(T));
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum");
}

}

}
}
}
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

If you debug the code, you will see that the static constructor is only
executed once. Instead the same exception that the static constructor
threw is rethrown when trying to create another instance of the class.

Christof said:
The first call of new MyList<int> also throws an exception, but that is
handled by the empty catch-block. Then the class MyList<int> is still not
constructed. So the static constructor is also triggered by the second
MyList<int>.

rvmaccount said:
It seems the static constructor is supposed to be called, ONLY once for a
particular type. If that's the case, why does the following code throws an
exception?

using System;
using System.Collections.Generic;
using System.IO;

namespace GenericTypes
{
class Program
{
static void Main(string[] args)
{

MyList<int> lList;
try
{
lList = new MyList<int>();
}
catch
{
}
//Following line throws an error
//should the static constructor, be not called for this
instance?
MyList<int> lList1 = new MyList<int>();
try
{
MyList<double> ldblList = new MyList<double>();
}
catch
{
}

}

class MyList<T>
{
static int i;
static List<T> _myList;
static MyList()
{
_myList = new List<T>();
System.Console.WriteLine("Called for " + typeof(T));
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enum");
}

}

}
}
}
 
J

Jon Skeet [C# MVP]

The first call of new MyList<int> also throws an exception, but that is
handled by the empty catch-block. Then the class MyList<int> is still not
constructed. So the static constructor is also triggered by the second
MyList<int>.

No, it's not. The system remembers that the code threw an exception,
and rethrows it. Put a Console.WriteLine in the static constructor -
you'll only see it executed once.

This is not a generics issue, btw. Here's some non-generic code:

using System;

class Broken
{
static Broken()
{
Console.WriteLine ("In static constructor");
throw new Exception("From static constructor");
}

public static void Foo()
{
}
}

class Test
{
static void Main()
{
try
{
Broken.Foo();
}

catch (Exception e)
{
Console.WriteLine(e);
}

try
{
Broken.Foo();
}

catch (Exception e)
{
Console.WriteLine(e);
}
}
}

Jon
 
G

Guest

What might be the reason for the system to "Remember" the exception. Is it
because, as Goran mentions, that as the class is not usable, so the system
throws the exception?
 
J

Jon Skeet [C# MVP]

What might be the reason for the system to "Remember" the exception. Is it
because, as Goran mentions, that as the class is not usable, so the system
throws the exception?

Exactly. I don't have the CLI spec on hand to check whether it's
documented, but if a type has failed to initialize, it wouldn't be a
good idea to try that initialization repeatedly.

Jon
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Jon said:
Exactly. I don't have the CLI spec on hand to check whether it's
documented, but if a type has failed to initialize, it wouldn't be a
good idea to try that initialization repeatedly.

Jon

Also, the static constructor is supposed to be executed only once, not
every time there is an attempt to use the class until it succeeds.

Normally a static constructor should never throw an exception. It's not
specified exactly when a static constructor has to be executed, only
that it is executed before anything in the class is used the first time.
Therefore it's impossible to safely catch that exception, as the CLI can
choose to execute the static constructor before the first line of your
main program code.

So, if you have any initialisation that might fail under normal
circumstances, you shouldn't do that in the static constructor.
 
J

Jon Skeet [C# MVP]

Göran Andersson said:
Also, the static constructor is supposed to be executed only once, not
every time there is an attempt to use the class until it succeeds.

Normally a static constructor should never throw an exception. It's not
specified exactly when a static constructor has to be executed, only
that it is executed before anything in the class is used the first time.

Well, static constructors are specified to execute *immediately* before
the class is used for the first time. Static initializers in a class
without a static constructor are certainly executed in a "looser"
fashion.
Therefore it's impossible to safely catch that exception, as the CLI can
choose to execute the static constructor before the first line of your
main program code.

That depends what the first line of code is :)
So, if you have any initialisation that might fail under normal
circumstances, you shouldn't do that in the static constructor.

Agreed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top