示例#1
0
        private string GetIncludePath(ModelWeavingContext context)
        {
            var modelTypeDef  = context.ModelTypeDef;
            var relationships = GetEagerRelationships(context, modelTypeDef, string.Empty, new[] { modelTypeDef });

            return(string.Join(",", relationships));
        }
示例#2
0
        public void Execute()
        {
            PrintIntro();
            LoadTypeDefinitions();
            FindModels();

            foreach (var modelTypeDef in _modelTypeDefs)
            {
                LogInfo($"Weaving type {modelTypeDef.FullName}...");
                var context = new ModelWeavingContext(
                    modelTypeDef,
                    LogDebug,
                    LogInfo,
                    LogWarning,
                    LogWarningPoint,
                    LogError,
                    LogWarningPoint);

                AddSessionField(context);
                AddIncludePathField(context);
                AddSessionManagedProperty(context);
                WeaveId(context);
                if (context.IdPropDef != null)
                {
                    AddResourceIdentifierProperty(context);
                    AddInitialize(context);
                    AddStaticCtor(context);
                    WeaveMeta(context);
                    WeaveHasOneIds(context);
                    WeaveHasOnes(context);
                    WeaveHasManyIds(context);
                    WeaveHasManys(context);
                }
            }
        }
示例#3
0
 private void AddSessionField(ModelWeavingContext context)
 {
     context.SessionField = AddField(
         "session",
         _sessionTypeDef,
         FieldAttributes.Private,
         context);
 }
示例#4
0
 private void AddIncludePathField(ModelWeavingContext context)
 {
     context.IncludePathField = AddField(
         "include",
         TypeSystem.String,
         FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly,
         context);
 }
示例#5
0
        private void WeaveId(ModelWeavingContext context)
        {
            if (context.IdPropDef != null &&
                context.IdPropDef.PropertyType.Resolve() != context.ImportReference(typeof(Guid)).Resolve())
            {
                LogError($"[Id] property must have a {typeof(Guid).FullName} getter: {context.IdPropDef.FullName}");
            }

            // if id property doesn't have a setter, try to add one
            if (context.IdPropDef != null)
            {
                LogInfo($"Upserting [Id] property setter: {context.IdPropDef.FullName} ");

                var idBackingField = context
                                     .IdPropDef
                                     ?.GetMethod
                                     ?.Body
                                     ?.Instructions
                                     ?.SingleOrDefault(x => x.OpCode == OpCodes.Ldfld)
                                     ?.Operand as FieldReference;

                var setter = context.IdPropDef.SetMethod;
                if (setter == null)
                {
                    setter = new MethodDefinition(
                        $"set_{context.IdPropDef.Name}",
                        MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                        context.ImportReference(TypeSystem.Void));
                    setter.Parameters.Add(
                        new ParameterDefinition(
                            "value",
                            ParameterAttributes.None,
                            context.IdPropDef.PropertyType));
                    setter.SemanticsAttributes = MethodSemanticsAttributes.Setter;
                    context.Methods.Add(setter);
                    context.IdPropDef.SetMethod = setter;
                }
                else
                {
                    setter.Body.Instructions.Clear();
                }
                var proc = setter.Body.GetILProcessor();

                var ret = proc.Create(OpCodes.Ret);

                proc.Emit(OpCodes.Ldarg_0); // load 'this' onto stack
                proc.Emit(OpCodes.Callvirt, context.SessionManagedProperty.GetMethod);
                proc.Emit(OpCodes.Brtrue_S, ret);

                proc.Emit(OpCodes.Ldarg_0);               // load 'this' onto stack
                proc.Emit(OpCodes.Ldarg_1);               // load 'value' onto stack
                proc.Emit(OpCodes.Stfld, idBackingField); // this.backingField = value;
                proc.Append(ret);                         // return

                LogInfo($"Successfully added updated setter for {context.IdPropDef}");
            }
        }
示例#6
0
        //TODO: this might be the fugliest algo ever written.  maybe clean this up
        private IEnumerable <string> GetEagerRelationships(
            ModelWeavingContext context,
            TypeDefinition type,
            string path,
            TypeDefinition[] pathTypes)
        {
            var eagerRltns = type.Properties
                             .Where(x => x.CustomAttributes
                                    .Where(attr =>
                                           attr.AttributeType.Resolve() == context.ImportReference(_hasOneAttributeTypeDef).Resolve() ||
                                           attr.AttributeType.Resolve() == context.ImportReference(_hasManyAttributeTypeDef).Resolve())
                                    .Where(attr => attr.HasConstructorArguments)
                                    .SelectMany(attr => attr.ConstructorArguments
                                                .Where(arg => arg.Type.Resolve() == context.ImportReference(_loadStrategyTypeDef).Resolve()))
                                    .Any(arg => (int)arg.Value == 1)) // eager
                             .Where(eagerProp =>
            {
                var eagerPropAttr = eagerProp.CustomAttributes.ContainsAttribute(Constants.Attributes.HasOne)
                        ? Constants.Attributes.HasOne
                        : Constants.Attributes.HasMany;
                var eagerPropName = eagerProp.JsonApiName(TypeSystem, eagerPropAttr);
                var eagerPropType = eagerProp.PropertyType.Resolve();
                var nextPath      = string.IsNullOrEmpty(path)
                        ? eagerPropName
                        : $"{path}.{eagerPropName}";
                var typeVisited = pathTypes.Contains(eagerPropType);
                if (typeVisited)
                {
                    LogWarning($"Potential circular reference detected and omitted from eager load: {eagerProp.PropertyType.Resolve().FullName}::{nextPath}");
                }
                return(!typeVisited);
            });

            if (eagerRltns.Any())
            {
                return(eagerRltns.SelectMany(x =>
                {
                    var eagerPropAttr = x.CustomAttributes.ContainsAttribute(Constants.Attributes.HasOne)
                            ? Constants.Attributes.HasOne
                            : Constants.Attributes.HasMany;
                    var eagerPropName = x.JsonApiName(TypeSystem, eagerPropAttr);
                    var eagerPropType = x.PropertyType.Resolve();
                    var nextPath = string.IsNullOrEmpty(path)
                            ? eagerPropName
                            : $"{path}.{eagerPropName}";
                    return GetEagerRelationships(
                        context,
                        x.PropertyType.Resolve(),
                        nextPath,
                        pathTypes.Concat(new[] { eagerPropType }).ToArray());
                })
                       .ToArray());
            }

            return(new[] { path });
        }
示例#7
0
 private void WeaveMeta(ModelWeavingContext context)
 {
     foreach (var propertyDef in context.MappedMeta)
     {
         if (propertyDef.CustomAttributes.ContainsAttribute(Constants.Attributes.Property))
         {
             LogError($"Property {propertyDef.FullName} cannot be included in both attributes and meta");
         }
     }
 }
示例#8
0
        private void AddSessionManagedProperty(ModelWeavingContext context)
        {
            var propertyName = "__argo__generated_SessionManaged";

            var getter = new MethodDefinition(
                $"get_{propertyName}",
                MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                context.ImportReference(typeof(bool)))
            {
                SemanticsAttributes = MethodSemanticsAttributes.Getter
            };

            var proc = getter.Body.GetILProcessor();

            proc.Body.Variables.Add(new VariableDefinition(context.ImportReference(typeof(bool))));

            var load0     = proc.Create(OpCodes.Ldc_I4_0);
            var storeLoc0 = proc.Create(OpCodes.Stloc_0);

            var loadRet = proc.Create(OpCodes.Ldloc_0);

            proc.Emit(OpCodes.Nop);

            //====== this.__argo__generated_session != null
            proc.Emit(OpCodes.Ldarg_0);
            proc.Emit(OpCodes.Ldfld, context.SessionField);
            proc.Emit(OpCodes.Brfalse_S, load0);
            //=============================================

            //====== !this.__argo__generated_session.Disposed
            proc.Emit(OpCodes.Ldarg_0);                                                    // push 'this' onto stack
            proc.Emit(OpCodes.Ldfld, context.SessionField);                                // push 'this.__argo__generated_session' onto stack
            proc.Emit(OpCodes.Callvirt, context.ImportReference(_session_DisposedGetter)); // push 'Disposed' value onto stack
            proc.Emit(OpCodes.Ldc_I4_0);
            proc.Emit(OpCodes.Ceq);
            proc.Emit(OpCodes.Br_S, storeLoc0);
            //===============================================

            proc.Append(load0);
            proc.Append(storeLoc0);
            proc.Emit(OpCodes.Br_S, loadRet);
            proc.Append(loadRet);
            proc.Emit(OpCodes.Ret);

            context.SessionManagedProperty = new PropertyDefinition(
                propertyName,
                PropertyAttributes.None,
                context.ImportReference(typeof(bool)))
            {
                GetMethod = getter
            };

            context.Methods.Add(getter);
            context.Properties.Add(context.SessionManagedProperty);
        }
示例#9
0
        private void WeaveReferenceGetter(
            ModelWeavingContext context,
            FieldReference backingField,
            FieldReference backingFieldInitialized,
            PropertyDefinition refPropDef,
            string attrName)
        {
            // supply generic type arguments to template
            var sessionGetAttr = _session_GetReference.MakeGenericMethod(context.ModelTypeDef, refPropDef.PropertyType);

            // get
            // {
            //   if (this.__argo__generated_session != null && !this.<[PropName]>k__BackingFieldInitialized)
            //   {
            //     this.<[PropName]>k__BackingField = this.__argo__generated_session.GetReference<[ModelType], [ReturnType]>(this, "[AttrName]");
            //     this.<[PropName]>k__BackingFieldInitialized = true;
            //   }
            //   return this.<[PropName]>k__BackingField;
            // }
            refPropDef.GetMethod.Body.Instructions.Clear();
            var proc = refPropDef.GetMethod.Body.GetILProcessor();

            var returnField = proc.Create(OpCodes.Ldarg_0);

            proc.Emit(OpCodes.Ldarg_0);                        // load 'this' onto stack
            proc.Emit(OpCodes.Ldfld, context.SessionField);    // load __argo__generated_session field from 'this'
            proc.Emit(OpCodes.Brfalse, returnField);           // if __argo__generated_session != null continue, else returnField

            proc.Emit(OpCodes.Ldarg_0);                        // load 'this' onto stack
            proc.Emit(OpCodes.Ldfld, backingFieldInitialized); // load <[PropName]>k__BackingFieldInitialized from 'this'
            proc.Emit(OpCodes.Brtrue, returnField);            // !this.<[PropName]>k__BackingFieldInitialized continue, else returnField

            proc.Emit(OpCodes.Ldarg_0);                        // load 'this' to reference backing field

            proc.Emit(OpCodes.Ldarg_0);                        // load 'this' onto stack to reference session field
            proc.Emit(OpCodes.Ldfld, context.SessionField);    // load __argo__generated_session field from 'this'
            proc.Emit(OpCodes.Ldarg_0);                        // load 'this'
            proc.Emit(OpCodes.Ldstr, attrName);                // load attrName onto stack
            proc.Emit(OpCodes.Callvirt, context.ImportReference(
                          sessionGetAttr,
                          refPropDef.PropertyType.IsGenericParameter
                    ? context.ModelTypeDef
                    : null));                                  // invoke session.GetReference(..)
            proc.Emit(OpCodes.Stfld, backingField);            // store return value in 'this'.<backing field>

            proc.Emit(OpCodes.Ldarg_0);                        // load 'this' onto stack
            proc.Emit(OpCodes.Ldc_I4_1);                       // load true (1) onto stack
            proc.Emit(OpCodes.Stfld, backingFieldInitialized); // store true in 'this'.<backing field>Initialized

            proc.Append(returnField);                          // load 'this' onto stack
            proc.Emit(OpCodes.Ldfld, backingField);            // load 'this'.<backing field>
            proc.Emit(OpCodes.Ret);                            // return
        }
示例#10
0
        private static FieldDefinition AddField(
            string fieldName,
            TypeReference fieldType,
            FieldAttributes attributes,
            ModelWeavingContext context)
        {
            var fieldDef = new FieldDefinition(
                $"__argo__generated_{fieldName}",
                attributes,
                context.ImportReference(fieldType));

            context.Fields.Add(fieldDef);
            return(fieldDef);
        }
示例#11
0
        private void WeaveHasManys(ModelWeavingContext context)
        {
            if (_session_GetGenericEnumerable == null ||
                _session_GetGenericCollection == null)
            {
                throw new Exception("Argo relationship weaving failed unexpectedly");
            }

            foreach (var propertyDef in context.MappedHasManys)
            {
                var propertyTypeRef = propertyDef.PropertyType;
                var propertyTypeDef = propertyTypeRef.Resolve();

                MethodReference getRltnMethRef;

                if (propertyTypeDef == context.ImportReference(typeof(IEnumerable <>)).Resolve())
                {
                    getRltnMethRef = _session_GetGenericEnumerable;
                }
                else if (propertyTypeDef == context.ImportReference(typeof(ICollection <>)).Resolve())
                {
                    getRltnMethRef = _session_GetGenericCollection;
                }
                else
                {
                    LogError($"Argo encountered a HasMany relationship on non IEnumerable<T> or ICollection<T> property {propertyDef.FullName}");
                    continue;
                }

                // get the backing field
                var backingField = propertyDef.BackingField();

                if (backingField == null)
                {
                    LogError($"Failed to load backing field for property {propertyDef.FullName}");
                    continue;
                }

                // find the rltnName, if there is one
                var rltnName = propertyDef.JsonApiName(TypeSystem, Constants.Attributes.HasMany);

                // find property generic element type
                var elementTypeDef = ((GenericInstanceType)propertyTypeRef).GenericArguments.First().Resolve();

                LogInfo($"\tWeaving {propertyDef} => {rltnName}");

                WeaveRltnGetter(context, backingField, propertyDef, elementTypeDef, getRltnMethRef, rltnName);
            }
        }
示例#12
0
        private static void WeaveRltnGetter(
            ModelWeavingContext context,
            FieldReference backingField,
            PropertyDefinition rltnPropDef,
            TypeReference elementTypeDef,
            MethodReference sessionGetRltnGeneric,
            string rltnName)
        {
            // supply generic type args to template
            var sessionGetRltn = sessionGetRltnGeneric.MakeGenericMethod(
                context.ModelTypeDef,
                elementTypeDef);

            rltnPropDef.GetMethod.Body.Instructions.Clear();

            var proc = rltnPropDef.GetMethod.Body.GetILProcessor();

            var endif = proc.Create(OpCodes.Ldarg_0);

            // TODO: this isn't thread safe - consider generating a Lazy in the ctor and invoking it here
            proc.Emit(OpCodes.Ldarg_0);
            proc.Emit(OpCodes.Ldfld, context.SessionField);
            proc.Emit(OpCodes.Brfalse_S, endif);
            proc.Emit(OpCodes.Ldarg_0);
            proc.Emit(OpCodes.Ldfld, backingField);
            proc.Emit(OpCodes.Brtrue_S, endif);

            proc.Emit(OpCodes.Ldarg_0);

            proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack to reference session field
            proc.Emit(OpCodes.Ldfld, context.SessionField); // load __argo__generated_session field from 'this'
            proc.Emit(OpCodes.Ldarg_0);                     // load 'this'
            proc.Emit(OpCodes.Ldstr, rltnName);             // load attrName onto stack
            proc.Emit(OpCodes.Callvirt, context.ImportReference(
                          sessionGetRltn,
                          rltnPropDef.PropertyType.IsGenericParameter
                    ? context.ModelTypeDef
                    : null));                       // invoke session.GetAttribute(..)

            proc.Emit(OpCodes.Stfld, backingField); // store return value in 'this'.<backing field>

            proc.Append(endif);
            proc.Emit(OpCodes.Ldfld, backingField);
            proc.Emit(OpCodes.Ret);
        }
示例#13
0
        private void WeaveHasManyIds(ModelWeavingContext context)
        {
            if (_session_GetRelationshipIds == null)
            {
                throw new Exception("Argo relationship id weaving failed unexpectedly");
            }

            foreach (var propertyDef in context.MappedHasManyIds)
            {
                if (propertyDef.PropertyType.Resolve() != context.ImportReference(typeof(IEnumerable)).Resolve() &&
                    propertyDef.PropertyType.Resolve() != context.ImportReference(typeof(IEnumerable <Guid>)).Resolve())
                {
                    LogError($"[HasManyIds] property must have a {typeof(IEnumerable).FullName} or {typeof(IEnumerable<Guid>).FullName} getter: {propertyDef.FullName}");
                }
                if (propertyDef.SetMethod != null)
                {
                    LogError($"[HasManyIds] property must not have a setter");
                }

                // get the backing field
                var backingField = propertyDef
                                   ?.GetMethod
                                   ?.Body
                                   ?.Instructions
                                   ?.SingleOrDefault(x => x.OpCode == OpCodes.Ldfld)
                                   ?.Operand as FieldReference;

                if (backingField == null)
                {
                    throw new Exception($"Failed to load backing field for property {propertyDef.FullName}");
                }

                // find the attrName, if there is one
                var attrName = propertyDef.JsonApiName(TypeSystem, Constants.Attributes.HasManyIds);

                LogInfo($"\tWeaving {propertyDef} => {attrName}");

                WeaveRelationshipIdsGetter(context, backingField, propertyDef, attrName);
            }
        }
示例#14
0
        private void WeaveAttributeFieldInitializers(
            ModelWeavingContext context,
            ILProcessor proc,
            IEnumerable <PropertyDefinition> attrPropDefs)
        {
            foreach (var attrPropDef in attrPropDefs)
            {
                // supply generic type arguments to template
                var sessionGetAttr = _session_GetAttribute
                                     .MakeGenericMethod(context.ModelTypeDef, attrPropDef.PropertyType);

                var backingField = attrPropDef.BackingField();

                if (backingField == null)
                {
                    throw new Exception($"Failed to load backing field for property {attrPropDef?.FullName}");
                }

                var propAttr = attrPropDef.CustomAttributes.GetAttribute(Constants.Attributes.Property);
                var attrName = propAttr.ConstructorArguments
                               .Select(x => x.Value as string)
                               .SingleOrDefault() ?? attrPropDef.Name.Camelize();

                proc.Emit(OpCodes.Ldarg_0);

                proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack to reference session field
                proc.Emit(OpCodes.Ldfld, context.SessionField); // load __argo__generated_session field from 'this'
                proc.Emit(OpCodes.Ldarg_0);                     // load 'this'
                proc.Emit(OpCodes.Ldstr, attrName);             // load attrName onto stack
                proc.Emit(OpCodes.Callvirt, context.ImportReference(
                              sessionGetAttr,
                              attrPropDef.PropertyType.IsGenericParameter
                        ? context.ModelTypeDef
                        : null));                       // invoke session.GetAttribute(..)

                proc.Emit(OpCodes.Stfld, backingField); // store return value in 'this'.<backing field>
            }
        }
示例#15
0
        private void WeaveHasOnes(ModelWeavingContext context)
        {
            if (_session_GetReference == null)
            {
                throw new Exception("Argo relationship weaving failed unexpectedly");
            }

            foreach (var propertyDef in context.MappedHasOnes)
            {
                // get the backing field
                var backingField = propertyDef.BackingField();

                if (backingField == null)
                {
                    throw new Exception($"Failed to load backing field for property {propertyDef.FullName}");
                }

                /* Add a boolean field to track whether the init was attempted.  A null check
                 * on the backing field is not good enough since they could have set the value to null. */
                var backingFieldInitialized = AddField(
                    backingField.Name + "Initialized",
                    TypeSystem.Boolean,
                    FieldAttributes.Private,
                    context);

                // find the attrName, if there is one
                var attrName = propertyDef.JsonApiName(TypeSystem, Constants.Attributes.HasOne);

                LogInfo($"\tWeaving {propertyDef} => {attrName}");

                WeaveReferenceGetter(context, backingField, backingFieldInitialized, propertyDef, attrName);
                if (propertyDef.SetMethod == null)
                {
                    return;
                }
                WeaveReferenceSetter(backingField, backingFieldInitialized, propertyDef);
            }
        }
示例#16
0
文件: CtorWeaver.cs 项目: engenb/Argo
        private void AddStaticCtor(ModelWeavingContext context)
        {
            var ctor = context.ModelTypeDef.GetStaticConstructor();

            var include = GetIncludePath(context);

            if (ctor == null)
            {
                ctor = new MethodDefinition(
                    ".cctor",
                    MethodAttributes.Private |
                    MethodAttributes.HideBySig |
                    MethodAttributes.Static |
                    MethodAttributes.SpecialName |
                    MethodAttributes.RTSpecialName,
                    TypeSystem.Void);

                context.Methods.Add(ctor);

                var proc = ctor.Body.GetILProcessor();

                proc.Emit(OpCodes.Ldstr, include);
                proc.Emit(OpCodes.Stsfld, context.IncludePathField);
                proc.Emit(OpCodes.Ret);
            }
            else
            {
                var proc          = ctor.Body.GetILProcessor();
                var originalFirst = ctor.Body.Instructions[0];

                proc.InsertBefore(originalFirst, proc.Create(OpCodes.Ldstr, include));
                proc.InsertBefore(originalFirst, proc.Create(OpCodes.Stsfld, context.IncludePathField));
            }

            context.ModelTypeDef.IsBeforeFieldInit = false;
        }
示例#17
0
 private void AddResourceIdentifierProperty(ModelWeavingContext context)
 {
     context.ResourcePropDef = AddAutoProperty("__argo__generated_Resource", context);
 }
示例#18
0
        private PropertyDefinition AddAutoProperty(string propertyName, ModelWeavingContext context)
        {
            var backingField = new FieldDefinition(
                $"<{propertyName}>k__BackingField",
                FieldAttributes.Private,
                context.ImportReference(_resourceIdentifierTypeDef));

            backingField.CustomAttributes.Add(new CustomAttribute(context.ImportReference(_compilerGeneratedAttribute)));
            backingField.CustomAttributes.Add(new CustomAttribute(context.ImportReference(_debuggerBrowsableAttribute))
            {
                ConstructorArguments =
                {
                    new CustomAttributeArgument(
                        context.ImportReference(_debuggerBrowsableStateTypeDef),
                        DebuggerBrowsableState.Collapsed)
                }
            });

            var getter = new MethodDefinition(
                $"get_{propertyName}",
                MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                context.ImportReference(_resourceIdentifierTypeDef))
            {
                SemanticsAttributes = MethodSemanticsAttributes.Getter
            };

            var getterProc = getter.Body.GetILProcessor();

            getterProc.Emit(OpCodes.Ldarg_0);             // load 'this' onto stack
            getterProc.Emit(OpCodes.Ldfld, backingField); // load <__argo__generated_Resource>k__BackingField onto stack
            getterProc.Emit(OpCodes.Ret);                 // return this.<__argo__generated_Resource>k__BackingField;

            var setter = new MethodDefinition(
                $"set_{propertyName}",
                MethodAttributes.Private | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                context.ImportReference(TypeSystem.Void))
            {
                SemanticsAttributes = MethodSemanticsAttributes.Setter,
                Parameters          =
                {
                    new ParameterDefinition(
                        "value",
                        ParameterAttributes.None,
                        context.ImportReference(_resourceIdentifierTypeDef))
                }
            };

            var setterProc = setter.Body.GetILProcessor();

            setterProc.Emit(OpCodes.Ldarg_0);             // load 'this' onto stack
            setterProc.Emit(OpCodes.Ldarg_1);             // load 'value' onto stack
            setterProc.Emit(OpCodes.Stfld, backingField); // this.<__argo__generated_Resource>k__BackingField = value;
            setterProc.Emit(OpCodes.Ret);                 // return;

            var propDef = new PropertyDefinition(
                propertyName,
                PropertyAttributes.None,
                context.ImportReference(_resourceIdentifierTypeDef))
            {
                GetMethod = getter,
                SetMethod = setter
            };

            context.Fields.Add(backingField);
            context.Methods.Add(getter);
            context.Methods.Add(setter);
            context.Properties.Add(propDef);

            return(propDef);
        }
示例#19
0
        private void AddInitialize(ModelWeavingContext context)
        {
            // public void __argo__generated_Initialize(IResourceIdentifier resource, IModelSession session)
            // {
            //   this.__argo__generated_Resource = resource;
            //   this.__argo__generated_session = session;
            //   this.__argo__generated_includePath = "model.include.path";
            //   this.Id = __argo__generated_session.GetId<TModel>();
            //  }
            var initialize = new MethodDefinition(
                "__argo__generated_Initialize",
                MethodAttributes.Public,
                TypeSystem.Void);

            initialize.Parameters.Add(
                new ParameterDefinition(
                    "resource",
                    ParameterAttributes.None,
                    context.ImportReference(_resourceIdentifierTypeDef)));
            initialize.Parameters.Add(
                new ParameterDefinition(
                    "session",
                    ParameterAttributes.None,
                    context.ImportReference(_sessionTypeDef)));

            var idBackingField = context
                                 .IdPropDef
                                 ?.GetMethod
                                 ?.Body
                                 ?.Instructions
                                 ?.SingleOrDefault(x => x.OpCode == OpCodes.Ldfld)
                                 ?.Operand as FieldReference;
            // supply generic type arguments to template
            var sessionGetId = _session_GetId.MakeGenericMethod(context.ModelTypeDef);

            var proc = initialize.Body.GetILProcessor();

            proc.Emit(OpCodes.Ldarg_0); // load 'this' onto stack
            proc.Emit(OpCodes.Ldarg_1); // load arg 'resource' onto stack
            proc.Emit(OpCodes.Callvirt, context.ResourcePropDef.SetMethod);

            proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack
            proc.Emit(OpCodes.Ldarg_2);                     // load arg 'session' onto stack
            proc.Emit(OpCodes.Stfld, context.SessionField); // this.__argo__generated_session = session;

            proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack
            proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack
            proc.Emit(OpCodes.Ldfld, context.SessionField); // load this.__argo__generated_session
            proc.Emit(OpCodes.Ldarg_0);                     // load 'this' onto stack
            proc.Emit(OpCodes.Callvirt, context.ImportReference(sessionGetId));
            proc.Emit(OpCodes.Stfld, idBackingField);       // this.<Id>K_backingField = this.__argo__generated_session.GetId<TModel>();

            // this._attrBackingField = this.__argo__generated_session.GetAttribute
            WeaveAttributeFieldInitializers(context, proc, context.MappedAttributes);

            // this._attrBackingField = this.__argo__generated_session.GetMeta
            WeaveMetaFieldInitializers(context, proc, context.MappedMeta);

            proc.Emit(OpCodes.Ret); // return

            context.Methods.Add(initialize);
        }