public ModelTypeProviderFields()

in src/AutoRest.CSharp/Common/Output/Models/Types/ModelTypeProviderFields.cs [37:157]


        public ModelTypeProviderFields(IReadOnlyList<InputModelProperty> properties, string modelName, InputModelTypeUsage inputModelUsage, TypeFactory typeFactory, ModelTypeMapping? modelTypeMapping, InputType? additionalPropertiesValueType, bool isStruct, bool isPropertyBag)
        {
            var fields = new List<FieldDeclaration>();
            var fieldsToInputs = new Dictionary<FieldDeclaration, InputModelProperty>();
            var publicParameters = new List<Parameter>();
            var serializationParameters = new List<Parameter>();
            var parametersToFields = new Dictionary<string, FieldDeclaration>();

            var visitedMembers = new HashSet<ISymbol>(SymbolEqualityComparer.Default);
            foreach (var inputModelProperty in properties)
            {
                var originalFieldName = BuilderHelpers.DisambiguateName(modelName, inputModelProperty.Name.ToCleanName(), "Property");
                var propertyType = GetPropertyDefaultType(inputModelUsage, inputModelProperty, typeFactory);

                // We represent property being optional by making it nullable (when it is a value type)
                // Except in the case of collection where there is a special handling
                var optionalViaNullability = inputModelProperty is { IsRequired: false} && inputModelProperty.Type is not InputNullableType &&
                                             !propertyType.IsCollection;

                var existingMember = modelTypeMapping?.GetMemberByOriginalName(originalFieldName);
                var serializationFormat = SerializationBuilder.GetSerializationFormat(inputModelProperty.Type);
                var field = existingMember is not null
                    ? CreateFieldFromExisting(existingMember, propertyType, GetPropertyInitializationValue(propertyType, inputModelProperty), serializationFormat, typeFactory, inputModelProperty.IsRequired, optionalViaNullability)
                    : CreateField(originalFieldName, propertyType, inputModelUsage, inputModelProperty, isStruct, isPropertyBag, optionalViaNullability);

                if (existingMember is not null)
                {
                    visitedMembers.Add(existingMember);
                }

                fields.Add(field);
                fieldsToInputs[field] = inputModelProperty;

                var parameterName = field.Name.ToVariableName();
                var parameterValidation = GetParameterValidation(field, inputModelProperty);
                var parameter = new Parameter(
                    Name: parameterName,
                    Description: FormattableStringHelpers.FromString(BuilderHelpers.EscapeXmlDocDescription(DocHelpers.GetDescription(inputModelProperty.Summary, inputModelProperty.Doc) ?? string.Empty)),
                    Type: field.Type,
                    DefaultValue: null,
                    Validation: parameterValidation,
                    Initializer: null);
                parametersToFields[parameter.Name] = field;
                // all properties should be included in the serialization ctor
                serializationParameters.Add(parameter with { Validation = ValidationType.None });

                // for classes, only required + not readonly + not constant + not discriminator could get into the public ctor
                // for structs, all properties must be set in the public ctor
                if (isStruct || inputModelProperty is { IsRequired: true, IsDiscriminator: false, ConstantValue: null })
                {
                    // [TODO]: Provide a flag to add read/write properties to the public model constructor
                    if (Configuration.Generation1ConvenienceClient || !inputModelProperty.IsReadOnly)
                    {
                        publicParameters.Add(parameter with { Type = parameter.Type.InputType });
                    }
                }
            }

            if (additionalPropertiesValueType is not null)
            {
                // We use a $ prefix here as AdditionalProperties comes from a swagger concept
                // and not a swagger model/operation name to disambiguate from a possible property with
                // the same name.
                var existingMember = modelTypeMapping?.GetMemberByOriginalName("$AdditionalProperties");

                var type = CreateAdditionalPropertiesPropertyType(typeFactory, additionalPropertiesValueType);
                if (!inputModelUsage.HasFlag(InputModelTypeUsage.Input))
                {
                    type = type.OutputType;
                }

                var name = existingMember is null ? "AdditionalProperties" : existingMember.Name;
                var declaration = new CodeWriterDeclaration(name);
                declaration.SetActualName(name);

                var accessModifiers = existingMember is null ? Public : GetAccessModifiers(existingMember);

                var additionalPropertiesField = new FieldDeclaration($"Additional Properties", accessModifiers | ReadOnly, type, type, declaration, null, false, SerializationFormat.Default, true);
                var additionalPropertiesParameter = new Parameter(name.ToVariableName(), $"Additional Properties", type, null, ValidationType.None, null);

                // we intentionally do not add this field into the field list to avoid cyclic references
                serializationParameters.Add(additionalPropertiesParameter);
                if (isStruct)
                {
                    publicParameters.Add(additionalPropertiesParameter with { Validation = ValidationType.AssertNotNull });
                }

                parametersToFields[additionalPropertiesParameter.Name] = additionalPropertiesField;

                AdditionalProperties = additionalPropertiesField;
            }

            // adding the leftover members from the source type
            if (modelTypeMapping is not null)
            {
                foreach (var existingMember in modelTypeMapping.GetPropertiesWithSerialization())
                {
                    if (visitedMembers.Contains(existingMember))
                    {
                        continue;
                    }
                    var existingCSharpType = BuilderHelpers.GetTypeFromExisting(existingMember, typeof(object), typeFactory);

                    // since the property doesn't exist in the input type, we use type of existing member both as original and field type
                    // the serialization will be generated for this type and it might has issues if the type is not recognized properly.
                    // but customer could always use the `CodeGenMemberSerializationHooks` attribute to override those incorrect serialization/deserialization code.
                    var field = CreateFieldFromExisting(existingMember, existingCSharpType, null, SerializationFormat.Default, typeFactory, false, false);
                    var parameter = new Parameter(field.Name.ToVariableName(), $"", field.Type, null, ValidationType.None, null);

                    fields.Add(field);
                    serializationParameters.Add(parameter);
                }
            }

            _fields = fields;
            _fieldsToInputs = fieldsToInputs;
            _parameterNamesToFields = parametersToFields;

            PublicConstructorParameters = publicParameters;
            SerializationParameters = serializationParameters;
        }