Generics: force type initialiser of T

M

Marc Gravell

Given a generic method "of T", is there a good way of ensuring that any
static ctor on T has executed? Following code demonstrates (TestClass1)
that via generics you can use the Type instance long before the static
ctor fires.

With a generic class and the "new()" clause, I can force this in the
static ctor of the generic class, but this is not always convenient,
plus may (possibly?) be seen as a no-op [not sure here].

Sample; ideally I'd get "Static ctor 1" to output before the type-name
of 1 (as per the second test), without using any hacks...

Marc

using System;
class Prog {
static void Main() {
GenMethod<TestClass1>();
GenClass<TestClass2>.Method();
}
static void GenMethod<T>() {
Console.WriteLine("GenMethod" + typeof(T).FullName);
}
}
class GenClass<T> where T : new()
{
static GenClass() { // possibly set noinlining
new T(); // throw away; forces T's static ctor
}
public static void Method() {
Console.WriteLine("Method: " + typeof(T).FullName);
}
}
class TestClass1 {
static TestClass1() {
Console.WriteLine("Static ctor 1");
}
}
class TestClass2 {
static TestClass2() {
Console.WriteLine("Static ctor 2");
}
}
 
D

Dustin Campbell

Given a generic method "of T", is there a good way of ensuring that
any static ctor on T has executed? Following code demonstrates
(TestClass1) that via generics you can use the Type instance long
before the static ctor fires.

With a generic class and the "new()" clause, I can force this in the
static ctor of the generic class, but this is not always convenient,
plus may (possibly?) be seen as a no-op [not sure here].

Sample; ideally I'd get "Static ctor 1" to output before the type-name
of 1 (as per the second test), without using any hacks...

Hmmm... I haven't found a way to do this. You can't use reflection to do
this because invoking a type initializer is disallowed. For example, this
fails:

static GenClass()
{
ConstructorInfo staticConstructor = typeof(T).GetConstructor(BindingFlags.Static
| BindingFlags.NonPublic, null, Type.EmptyTypes, null);
staticConstructor.Invoke(null);
}

However, the type initializers is guaranteed to be when the type is accessed
in such a way that initialization is required. So, you could have a dummy
static method that is called via reflection:

using System;
using System.Reflection;

class Program
{
static void Main()
{
GenMethod<TestClass1>();
GenClass<TestClass2>.Method();
}
static void GenMethod<T>()
{
Console.WriteLine("GenMethod" + typeof(T).FullName);
}
}
class GenClass<T> where T: new()
{
static GenClass()
{
MethodInfo dummyMethod = typeof(T).GetMethod("DummyMethod", BindingFlags.Static
| BindingFlags.NonPublic, null, Type.EmptyTypes, null);
dummyMethod.Invoke(null, null);
}
public static void Method()
{
Console.WriteLine("Method: " + typeof(T).FullName);
}
}
class TestClass1
{
static void DummyMethod() { }
static TestClass1()
{
Console.WriteLine("Static ctor 1");
}
}
class TestClass2
{
static void DummyMethod() { }
static TestClass2()
{
Console.WriteLine("Static ctor 2");
}
}

My big question is, why do you want to do this? If you're trying to get type
initializers to be called in some sort of deterministic way, it might be
an indication that you need a different design.

Best Regards,
Dustin Campbell
Developer Express Inc
 
M

Marc Gravell

That is more or less where I got to... I'll avoid the reflection,
though - seems a bit scrappy : but thanks all the same.

The why is complex, and relates to registering a few interfaces with a
lookup (dictionary mapping interfaces to instances implementing that
interface), for use e.g. by some generic lazy-loading, where the "thing
doing the loading" (i.e. an uninitialised collection of orders) knows
how to get its data in terms of interfaces (providers / adapters for
want of a better term), but doesn't know who (which specific class)
will be providing the data. Until I applied the "new()" bit, in a few
test cases no class was registering itself as the provider in time for
the lazy lookup, so it was failing (gracefully).

With the fix, things are correctly saying "hey, I exist and can do
<x>"...

The main objective is to do lazy loading where it doesn't care if it
has direct (SqlClient) or indirect (WSDL etc) access to the data - as
long as the concrete class meets the interface correctly.

Of course, if you care to cite a pattern to look at?

Marc
 
G

Guest

I know this is kinda hokey, but:

class TestClass2 {
public static bool Initialized=false;
static TestClass2() {
Initialized=true;
Console.WriteLine("Static ctor 2");
}
}

I wonder if that would be usable...

Peter
 
B

Bruce Wood

Marc said:
That is more or less where I got to... I'll avoid the reflection,
though - seems a bit scrappy : but thanks all the same.

The why is complex, and relates to registering a few interfaces with a
lookup (dictionary mapping interfaces to instances implementing that
interface), for use e.g. by some generic lazy-loading, where the "thing
doing the loading" (i.e. an uninitialised collection of orders) knows
how to get its data in terms of interfaces (providers / adapters for
want of a better term), but doesn't know who (which specific class)
will be providing the data. Until I applied the "new()" bit, in a few
test cases no class was registering itself as the provider in time for
the lazy lookup, so it was failing (gracefully).

With the fix, things are correctly saying "hey, I exist and can do
<x>"...

Perhaps I'm being too traditional with this approach, but I would solve
this problem by taking it out "from under the covers" as it were. If
the problem is to register a bunch of classes against some interfaces
and thus to achieve some sort of dynamic loading scenario ("I loaded
this assembly and now I can do these things....") then perhaps this is
something to do explicitly in code, rather than trying to make it
happen "magically" under the covers.

In brief, perhaps you've outsmarted yourself. I do it all the time. :)

Let's say that you want to load an assembly and then register all of
the classes in it with your dictionary, so that you know which
interfaces have implementations in that assembly, and which classes
correspond to which interfaces. I would put a sealed class called
"RegisterCapabilities" (or something equally illuminating) into the
assembly, and give it one static method, something like "Register". The
Register method would register all of the classes in the assembly with
the dictionary, either by doing so explicitly (my personal choice) or
by calling each class and asking it to register itself.

Then, when your application loads an assembly, it should call
RegisterCapabilities.Register() as its first act. If the assembly
doesn't contain that class and static method, then it's malformed and
can't be used.

If you're not dynamically loading the assembly, then your main program
can do this as the first thing it does, since the correct routine to
call is already known.

Since the registration is now explicit in code, you can easily ensure
that it's happening at the right place without any jiggery-pokery in
static initializers. I think that this solution would also be easier to
maintain: the code is explicit and it's easy to see what it does (and
easy to debug if it fails).

As I said: perhaps that solution is too clunky. I tend to prefer things
out where I can see them... every time I've experimented with clever,
under-the-covers, "magic" solutions to problems, those solutions have
come back to bite me.... :)
 
M

Marc Gravell

No - I think you are right; me outsmarting myself... this is more or
less what I currently have in my "Main()" and my "global.asax"
respectively (give or take some abstraction to some wrapper methods).

The new() trick was helpful in a scenario where the provider (in this
case) actually just wrapped functionality from other services, so the
provider itself could be safely abstracted down to the lower layers...
but by the same token, there is no harm in registering it explicitely
in the upper layers, or just calling a Register() method.

But I think you pretty much hit what I was concluding myeslf... just
about doable, but why make life tricky for myself ;-p

Cheers for input,

Marc
 
M

Marc Gravell

In the static case, yes, but I was referring to the generic case where
the concrete type (TestClass2) is not explicitely known (except as "T")
at dll-compile-time (the "T" being provided by a referencing assembly).
Of course, if C# supported static interfaces we might be able to do
something.

But I think I'm sorted; cheers for the input,

Marc
 
C

Chris Nahr

Given a generic method "of T", is there a good way of ensuring that any
static ctor on T has executed? Following code demonstrates (TestClass1)
that via generics you can use the Type instance long before the static
ctor fires.

You're barking up the wrong tree. There's nothing different between
generics and non-generics regarding the execution of static ctors.

The actual issue demonstrated by your sample code is the fact that
TYPE REFLECTION (via typeof) does not trigger the static ctor. To my
knowledge, it was never supposed to do that.

As an illustration, insert the following method call at the first line
of your Main method:

Console.WriteLine(typeof(TestClass1).FullName);

You will notice that even with this NON-GENERIC call, the static ctor
of TestClass1 does not execute. That's because you're merely doing
reflection. Generics have nothing to do with it.
 
M

Marc Gravell

With all due respect, I know full well which trees I am barking at.

I didn't suggest that looking at the Type object does (or should) trigger
the static ctor executior; I merely asked whether it was possible to force
the type initialiser to run (if it hasn't already), specifically in the case
where the type in question was a generic.

Generics has *everything* to do with it. If it wasn't for generics, I could
simply call a ForceInit() (no-op) static method to force the static ctor to
load.

Marc
 
C

Chris Nahr

In that case I'm sorry for the misunderstanding.

In your original code example, the static ctor was not executed
because the only type access was via typeof() calls. So I mistakenly
assumed your goal was to execute static ctors before typeof() calls.

Your last paragraph in this post states your real question much more
succinctly, and I see that all relevant things have already been said.
 
D

Dustin Campbell

No - I think you are right; me outsmarting myself...

:) Occasionally, I'll be working on a design and run into some sort of snare.
Then, when coming back to the design (after spending some time away), I'll
discover that I was just trying to be too clever.

Best Regards,
Dustin Campbell
Developer Express Inc.
 

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