1

Problem:
Class1.foo1 relies on Class2.foo2, but it can't be guaranteed they'll compile in an order that will allow class2.foo2 to have been initialized when referenced by Class1.foo1.

class Class1
{
    static Foo foo1 = new Foo("arg1", Class2.foo2);  
}
class Class2
{
    static Foo foo2 = new Foo("arg2");
}

Since Class2.foo2 has not be initialized when Class1.foo1 is created, the 'Class2.foo2' argument passed is simply null.

My Question:
Is there a known pattern to handle this sort of reliance scenario that doesn't require verbose initializers to be written for every field? I can throw as much code into the Foo class as needed to make it work because it only runs once at the beginning of the program, I'd just really like to keep it hidden away, because a great number of these fields need to be written.

What I've Read:
I've come across a few threads talking about lazy initialization which almost sounds appropriate in that it does something the first time an object is needed, and it's field specific, but it results in unwieldy code:

    static Foo _otherFoo;
    static Foo otherFoo
    {
        get
        {
            if (_otherFoo == null)
                return new Foo("arg2");
            else return _otherFoo;
        }
    }

I'd like to save my fellow developers from carpal tunnel. It wouldn't be a problem if all this bloat could be hidden behind a constructor:

public Foo(params Foo[] dependencies)
{
    if(anyItem in dependencies) == null
        anyItem = new Foo("Params are defined per-instance in the initializer. What goes here?");
}

But I can't know Class2.foo2's initialization parameters. Since this only runs once at startup, I decided to look into reflection as an option, but from what I've seen, reflection can't help you discern anything about a field's initializer, you can only get its value after it's been initialized.

It looks like the order of class initialization is determined by the order fields are accessed:
Is the order of static class initialization in C# deterministic?
So I ran some tests to see how this plays out, and it doesn't seem to halt initialization of fields in order to intialize their dependencies i.e. Class1.foo1's constructor must fully complete before Class2.foo2 gets initialized, which means Class2.foo2 will remain null.

My Question (again):
Is there a known pattern to handle this sort of reliance scenario that doesn't require verbose initializers to be written for every field?

Ian Gungee
  • 33
  • 4
  • 4
    So, why cant you do this in the static constructor where you can assert order? – TheGeneral Jul 30 '20 at 22:10
  • @TheGeneral I edited my question to make it more clear: these fields aren't guaranteed to be in the same class where a constructor could define their order. Even still, shouldn't the static field constructor be ordered by line number? – Ian Gungee Jul 30 '20 at 22:29
  • 1
    The `foo2` referenced in `class1` isn't `class2.foo2`. Make sure you're pasting compilable code. – madreflection Jul 30 '20 at 22:29
  • This is all outlined in the specs 15.5.6.2 Static field initialization – TheGeneral Jul 30 '20 at 22:56
  • 1
    "*The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration (§15.5.6.1). Within a partial class, the meaning of "textual order" is specified by §15.5.6.1. If a static constructor (§15.12) 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.*" – TheGeneral Jul 30 '20 at 22:56
  • 1
    If you have multiple static classes then this becomes more complicated and the initialisation order of the fields in the classes depends on what is accessed first ect. I personally think you shouldnt be relying on this, its hard to maintain and easy for someone to add fields and make a mistake – TheGeneral Jul 30 '20 at 22:59
  • @TheGeneral Hence the question. I recognize that *as is* this is incredibly unmaintainable and virtually guaranteed to break, so I was wondering if there was a known pattern that allowed this sort of variable declaration to *avoid* the inherent breakage. Some sort of cache of uninitialized fields to re-establish references to? I'll have to play around when I get a chance to sit down. – Ian Gungee Jul 31 '20 at 23:53

0 Answers0