Ejemplo n.º 1
0
        private void GenerateProperty(
            string containerName,
            PropertyTypeNode.TypeTag containerTypeTag,
            PropertyTypeNode propertyType,
            StringBuffer gen)
        {
            var propertyWrapperVariableName = $"s_{propertyType.Name}Property";
            var propertyTypeString          = TypeDeclarationStringForProperty(propertyType);

            if (!string.IsNullOrWhiteSpace(propertyType.IsInheritedFrom))
            {
                // Just add a propertybag member
                PropertyBagItemNames.Add(
                    $"new InheritedProperty<{propertyType.IsInheritedFrom}, {containerName}, {propertyTypeString}>({propertyWrapperVariableName})"
                    );
                return;
            }

            var propertyWrapperTypeName = GetPropertyWrapperTypeFor(
                containerName,
                containerTypeTag,
                propertyType);

            bool isCompositeType = PropertyTypeNode.IsCompositeType(propertyType.Tag);

            // Backing field if any

            var propertyAccessorName = string.Empty;
            var backingField         = GeneratePropertyBackingField(
                propertyType.Name,
                propertyType,
                out propertyAccessorName
                );

            if (!string.IsNullOrEmpty(backingField))
            {
                // If we have a class we delegate init to constructor otherwise we default construct here

                var initializer = GenerateInitializerFromProperty(propertyType);

                gen.Append(' ', Style.Space * 1);
                gen.Append(backingField);

                if (!string.IsNullOrEmpty(initializer))
                {
                    if (containerTypeTag == PropertyTypeNode.TypeTag.Struct)
                    {
                        gen.Append($"= {initializer}");
                    }
                    else
                    {
                        // Add an initializer for that
                        ConstructorInitializerFragments.Add(() => $"{propertyAccessorName} = {initializer};");
                    }
                }

                gen.Append($";{Environment.NewLine}");
            }

            // Public C# Property

            // @TODO extract as a method

            var containerAsAParamTokens = new List <String> {
            };

            if (containerTypeTag.HasFlag(PropertyTypeNode.TypeTag.Struct))
            {
                containerAsAParamTokens.Add("ref");
            }
            containerAsAParamTokens.Add("this");

            var getSetValueCallContainerParam = string.Join(" ", containerAsAParamTokens);

            gen.Append(' ', Style.Space * 1);
            var modifiers = string.Join(" ", ModifiersToStrings(AccessModifiers.Public));

            gen.Append($@"{modifiers} {propertyTypeString} {propertyType.Name}
        {{
            get {{ return {propertyWrapperVariableName}.GetValue({getSetValueCallContainerParam}); }}
            set {{ {
                    (isCompositeType ? string.Empty : $"{propertyWrapperVariableName}.SetValue({getSetValueCallContainerParam}, value);")
                } }}
        public override void OnPropertyGenerationStarted(PropertyTypeNode container, PropertyTypeNode property)
        {
            TypeDefinition type;

            if (!_typeDefinitionPerPropertyNodeMap.TryGetValue(container, out type))
            {
                // @TODO error
                return;
            }

            // Backing field (should be optional)

            var backingField = new FieldDefinition(
                BackingFieldFromPropertyName(property.PropertyName),
                FieldAttributes.Private,
                type.Module.ImportReference(property.NativeType)
                );

            type.Fields.Add(backingField);

            ConstructorInitializerFragments.Add(
                new CecilGenerationFragmentContext()
            {
                Module   = type.Module,
                Type     = type,
                Fragment = ilProcessor =>
                {
                    ilProcessor.Append(ilProcessor.Create(OpCodes.Ldarg_0));
                    ilProcessor.Append(ilProcessor.Create(OpCodes.Newobj, type.Module.ImportReference(property.NativeType)));
                    ilProcessor.Append(ilProcessor.Create(OpCodes.Stfld, backingField));
                }
            });

            // Property wrapper static field
            var propertyWrapperType = type.Module.ImportReference(GetPropertyWrapperTypeFor(container, property));

            var propertyWrapperField = new FieldDefinition(
                PropertyWrapperFieldName(property.PropertyName),
                FieldAttributes.Private | FieldAttributes.Static,
                propertyWrapperType
                );

            type.Fields.Add(propertyWrapperField);

            PropertyBagItemTypes.Add(propertyWrapperField);

            // TODO add a post processing field initialization

            ConstructorInitializerFragments.Add(
                new CecilGenerationFragmentContext()
            {
                Module   = type.Module,
                Type     = type,
                Fragment = ilProcessor =>
                {
                    ilProcessor.Append(ilProcessor.Create(OpCodes.Ldarg_0));

                    // #arg 0
                    ilProcessor.Append(ilProcessor.Create(OpCodes.Ldstr, property.PropertyName));

                    // #arg 1 (getter)
                    // #arg 2 (setter)
                    // #arg 2 (reference)
                }
            });

            /*
             * FloatListProperty =
             *  new ListProperty<TestContainer, List<float>, float>(nameof(FloatList),
             *      c => c._floatList,
             *      null,
             *      null);
             */

            // Accessor method

            var getPropertyMethod =
                new MethodDefinition(
                    "get_" + property.PropertyName,
                    MethodAttributes.Public |
                    MethodAttributes.HideBySig |
                    MethodAttributes.SpecialName |
                    MethodAttributes.RTSpecialName,
                    type.Module.ImportReference(property.NativeType)
                    );

            getPropertyMethod.Body.Variables.Add(
                new VariableDefinition(type.Module.ImportReference(typeof(PropertyBag))));

            //      get { return FloatListProperty.GetValue(this); }
            var il = getPropertyMethod.Body.GetILProcessor();

            il.Append(il.Create(OpCodes.Ldarg_0));
            il.Append(il.Create(OpCodes.Ldfld, propertyWrapperField));
            il.Append(il.Create(OpCodes.Ldarg_0));

            var getValueDelegateRef = propertyWrapperType.Resolve().Methods.FirstOrDefault(m => m.Name == "GetValue");

            il.Append(il.Create(OpCodes.Callvirt, type.Module.ImportReference(getValueDelegateRef)));
            il.Append(il.Create(OpCodes.Ret));

            type.Methods.Add(getPropertyMethod);

            // Actual property

            //      public List<float> FloatList
            var propertyAccessorForProperty = new PropertyDefinition(
                property.PropertyName,
                PropertyAttributes.None,
                type.Module.ImportReference(property.NativeType)
                )
            {
                HasThis   = true,
                GetMethod = getPropertyMethod,
            };

            type.Properties.Add(propertyAccessorForProperty);
        }