void GenerateApartFieldsProperties(IILDynamicType classImpl, Type interfaceType) { var apartFields = new Dictionary <string, IILField>(); var initializedFields = new Dictionary <string, IILField>(); var methods = RelationInfo.GetMethods(interfaceType); var properties = RelationInfo.GetProperties(interfaceType).ToArray(); foreach (var method in methods) { var name = method.Name; if (!name.StartsWith("get_") && !name.StartsWith("set_")) { continue; } IILField field; IILField initCheckField; var propName = RelationInfo.GetPersistentName(method.Name.Substring(4), properties); if (!_relationInfo.ApartFields.ContainsKey(propName)) { throw new BTDBException($"Invalid property name {propName}."); } if (!apartFields.TryGetValue(propName, out field)) { field = classImpl.DefineField("_" + propName, method.ReturnType, FieldAttributes.Private); apartFields[propName] = field; initCheckField = classImpl.DefineField("_initialized_" + propName, typeof(bool), FieldAttributes.Private); initializedFields[propName] = initCheckField; } else { initCheckField = initializedFields[propName]; } var reqMethod = classImpl.DefineMethod(method.Name, method.ReturnType, method.GetParameters().Select(pi => pi.ParameterType).ToArray(), MethodAttributes.Virtual | MethodAttributes.Public); if (name.StartsWith("set_")) { reqMethod.Generator.Ldarg(0).Ldarg(1).Stfld(field) .Ldarg(0).LdcI4(1).Stfld(initCheckField) .Ret(); } else { var initializedLabel = reqMethod.Generator.DefineLabel("initialized"); reqMethod.Generator .Ldarg(0).Ldfld(initCheckField) .Brtrue(initializedLabel) .Ldstr($"Cannot use uninitialized apart field {propName}") .Newobj(() => new BTDBException(null)) .Throw() .Mark(initializedLabel) .Ldarg(0).Ldfld(field).Ret(); } classImpl.DefineMethodOverride(reqMethod, method); } }