Goal
My goal is to implement a sealed, public nested class that can only be created by its enclosing class - without using reflection.
That means that the nested class cannot have any public or internal constructors or any public or internal static factory methods.
Previous Work
This post from a couple of years ago seems to be the answer. (That entire thread has a lot of information about what I'm trying to achieve.)
How it works is quite straightforward: It leverages the fact that a nested class can access the static fields of its enclosing class, along with a static constructor for the nested class.
The enclosing class declares a static Func<NestedClassType, NestedClassCtorArgType>
delegate which returns an instance of the nested class, so that the enclosing class can use that delegate as a factory method.
The nested class itself has a static constructor which initialises the enclosing class's static factory delegate to a delegate that will create an instance of the nested class.
The Problem
Unfortunately, I can't get it to work as it is written in that answer. The reason is that the static constructor for the nested class is not called before the enclosing class uses the factory method, and thus there is a null-reference exception. (If you look at the sample program at the end of this question you will see what I mean.)
My Workaround
I have worked around the problem as follows:
- Added to the nested class an internal static
Initialise()
method that does nothing. - Added to the enclosing class a static constructor that calls the nested class's
Initialise()
method.
This works fine, but it leaves a bit of a carbuncle in the shape of an internal static void Initialise()
method.
My Questions
Is there a way to avoid this way of doing it? I can't help but think I'm missing something from the original post that I linked above. Did I misunderstand the answer?
Is there a clever way to force the static constructor for the nested class to run before I call the code that tries to create an instance of the nested class?
And are there any other problems with this approach?
(I'm aware that I can just write a public interface for the nested class, and return that instead. This question isn't about solving it that way!)
The Sample Code
Here's my sample code. Try running it, and it will print "Test". Then try commenting-out the line that is marked <--- If you comment this out, things won't work
and run it again.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
Outer outer = new Outer();
Outer.Inner item = outer.Item("Test");
Console.WriteLine(item.Text);
}
}
public sealed class Outer
{
public Inner Item(string text)
{
return _nestedFactory(text);
}
// This static constructor calls the nested class's Initialise() method, which causes the
// nested class's static constructor to run, which then sets the enclosing class's
// _nestedFactory field appropriately.
static Outer()
{
Inner.Initialise(); // <--- If you comment this out, things won't work.
}
// This class has a private constructor.
// I only want class Outer to be able to create instances of it.
public sealed class Inner
{
private Inner(string value) // Secret private constructor!
{
text = value;
}
public string Text { get { return text; } }
static Inner()
{
_nestedFactory = text => new Inner(text);
}
internal static void Initialise(){}
readonly string text;
}
static Func<string, Inner> _nestedFactory;
}
}