コード例 #1
0
        static void EmitMergeMethodBody(EmitGenerator gen, GenericTypeParameterBuilder[] genParamBuilders,
                                        FieldBuilder[] depProviderFields)
        {
            // var myParams = context.Parameters;
            var myParams = gen.DeclareLocal(ParameterSetType);

            gen.LoadArgument(1);
            gen.CallMethod(GetInjectionContextParameters);
            gen.StoreLocal(myParams);

            #region If (myParams == null || myParams.Length == 0) condition

            // if (myParams == null || myParams.Length == 0) Goto myParamsIsNullLabel Else Goto myParamsIsNotNullAndLengthNotEqualTo0Label
            var myParamsIsNullLabel = gen.DefineLabel();
            var myParamsIsNotNullAndLengthNotEqualTo0Label = gen.DefineLabel();

            gen.LoadLocal(myParams);
            gen.IfFalseGoto(myParamsIsNullLabel);

            gen.LoadLocal(myParams);
            gen.CallMethod(GetParameterLength);
            gen.IfTrueGoto(myParamsIsNotNullAndLengthNotEqualTo0Label);

            #endregion

            var createObjectMethods = new MethodInfo[depProviderFields.Length];

            #region if (myParams == null || myParams.Length == 0) block

            gen.MarkLabel(myParamsIsNullLabel);
            for (int i = 0; i < depProviderFields.Length; i++)
            {
                // _dependency0.CreateObject(context, out param0);
                // _dependency1.CreateObject(context, out param1);
                // ...
                var depProviderField = depProviderFields[i];
                gen.LoadThis();
                gen.LoadField(depProviderField);
                gen.LoadArgument(1);     // load parameter [context]
                gen.LoadArgument(i + 2); // load parameter [param0], [param1], [param2]...
                var createObjectMethod = GetCreateObjectOfDependencyProviderMethod(depProviderField.FieldType);
                createObjectMethods[i] = createObjectMethod;
                gen.CallMethod(createObjectMethod);
            }

            gen.Return();

            #endregion

            #region if (myParams != null && myParams.Length != 0) block

            gen.MarkLabel(myParamsIsNotNullAndLengthNotEqualTo0Label);

            // var paramKind = myParams.ParameterKind;
            var paramKind = gen.DeclareLocal(typeof(ParameterKind));
            gen.LoadLocal(myParams);
            gen.CallMethod(GetParameterKind);
            gen.StoreLocal(paramKind);

            // (Ok)=====================================================

            var paramKindDefaultCase = gen.DefineLabel();
            var paramKindTable       = new Label[] { gen.DefineLabel(), gen.DefineLabel() };

            gen.LoadLocal(paramKind);
            gen.Switch(paramKindTable); // switch (paramKind)
            // case default Goto paramKindDefaultCase
            gen.Goto(paramKindDefaultCase);

            // (Ok)=====================================================

            #region case paramKind = ParameterKind.Positional (Ok)

            gen.MarkLabel(paramKindTable[0]);

            // var myParamLength = myParams.Length;
            var myParamLength = gen.DeclareLocal(typeof(int));
            gen.LoadLocal(myParams);
            gen.CallMethod(GetParameterLength);
            gen.StoreLocal(myParamLength);

            // switch (myParamLength)
            gen.LoadLocal(myParamLength);
            gen.LoadInt32(1);
            gen.Substrate(); // myParamLength - 1, this is because the switch branch is starting from 1, instead of 0

            var paramLengthDefaultCase = gen.DefineLabel();
            var paramLengthTable       = new Label[depProviderFields.Length];
            for (int i = 0; i < depProviderFields.Length; i++)
            {
                paramLengthTable[i] = gen.DefineLabel();
            }

            gen.Switch(paramLengthTable);
            // case default Goto paramLengthDefaultCase
            gen.Goto(paramLengthDefaultCase);

            #region case i for myParamLength

            for (int i = 0; i < depProviderFields.Length; i++)
            {
                gen.MarkLabel(paramLengthTable[i]);
                for (int j = 0; j < depProviderFields.Length; j++)
                {
                    if (j <= i)
                    {
                        // something like: param0 = GetPositionalDependencyObject(_depProvider0, myParams[0], context);
                        // load _depProvider0
                        gen.LoadThis();
                        gen.LoadField(depProviderFields[j]);

                        // load myParams[0]
                        gen.LoadLocal(myParams);
                        gen.LoadInt32(j);
                        gen.CallMethod(GetItem);

                        // load context
                        gen.LoadArgument(1);

                        var genParamType = genParamBuilders[j];
                        gen.CallMethod(OpenGetPositionalDependencyObjectMethod.MakeGenericMethod(genParamType));
                        //gen.StoreObject(genParamType);
                        gen.StoreArgument(j + 2);
                    }
                    else
                    {
                        // something like: _depProvider1.CreateObject(context, out param1);
                        // load _depProvider1
                        gen.LoadThis();
                        gen.LoadField(depProviderFields[j]);
                        // load context
                        gen.LoadArgument(1);
                        // load param1, its index is j + 2
                        gen.LoadArgument(j + 2);
                        gen.CallMethod(createObjectMethods[j]);
                    }
                }
                gen.Return();
            }

            #endregion

            #region default case for myParamLength

            gen.MarkLabel(paramLengthDefaultCase);
            gen.LoadArgument(1);
            gen.LoadInt32(depProviderFields.Length);
            gen.LoadLocal(myParams);
            gen.CallMethod(GetParameterLength);
            gen.CallMethod(ParameterNumberExceedsMethod);
            gen.Throw();

            #endregion

            gen.Return();

            #endregion

            #region case paramKind = ParameterKind.Named (Ok)

            gen.MarkLabel(paramKindTable[1]);
            for (int i = 0; i < depProviderFields.Length; i++)
            {
                // something like: param0 = GetNamedDependencyObject(_depProvider0, myParams, context);

                // load _depProvider0
                gen.LoadThis();
                //gen.LoadThis(); // why do we need this?
                gen.LoadField(depProviderFields[i]);

                // load myParams
                gen.LoadLocal(myParams);

                // load context
                gen.LoadArgument(1);

                var genParamType = genParamBuilders[i];
                gen.CallMethod(OpenGetNamedDependencyObjectMethod.MakeGenericMethod(genParamType));

                // store to param0, its parameter index is [i + 2]
                gen.StoreArgument(i + 2);
            }
            gen.Return();

            #endregion

            #region default case for ParameterKind (Ok)

            gen.MarkLabel(paramKindDefaultCase);
            gen.Throw(ImpossibleExceptionConstructor);

            #endregion

            gen.Return();

            #endregion
        }