Field initializer accessing 'this' reloaded

It isn't possible, in the general case, to determine whether an expression refers to the object being constructed, so prohibiting it and requiring compilers to diagnose it would require the impossible. Consider

partial class A {
  public static A Instance = CreateInstance();
  public int a = 3;
  public int b = Instance.a;
}

It's possible, and as far as I know perfectly valid, even if it a horrible idea, to create an object with FormatterServices.GetUninitializedObject(typeof(A)), set A.Instance to that, and then call the constructor. When b is initialised, the object reads its own a member.

partial class A {
  public static A CreateInstance() {
    Instance = (A)FormatterServices.GetUninitializedObject(typeof(A));
    var constructor = typeof(A).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
    var helperMethod = new DynamicMethod(string.Empty, typeof(void), new[] { typeof(A) }, typeof(A).Module, true);
    var ilGenerator = helperMethod.GetILGenerator();
    ilGenerator.Emit(OpCodes.Ldarg_0);
    ilGenerator.Emit(OpCodes.Call, constructor);
    ilGenerator.Emit(OpCodes.Ret);
    var constructorInvoker = (Action<A>)helperMethod.CreateDelegate(typeof(Action<A>));
    constructorInvoker(Instance);
    return Instance;
  }
}

static class Program {
  static void Main() {
    Console.WriteLine("A.Instance = (a={0}, b={1})", A.Instance.a, A.Instance.b);
  }
}

You can only get compiler errors for what's detectable at compile time.

Tags:

C#