private void WriteClassConstructor(IJsonClassGeneratorConfig config, StringBuilder sw, JsonType type, string indentMembers, string indentBodies) { // Write an empty constructor on a single-line: if (type.Fields.Count == 0) { sw.AppendFormat(indentMembers + "public {0}() {{}}{1}", type.AssignedName, Environment.NewLine); return; } // Constructor signature: { if (config.UseJsonAttributes) { sw.AppendLine(indentMembers + "[JsonConstructor]"); } sw.AppendFormat(indentMembers + "public {0}({1}", type.AssignedName, Environment.NewLine); FieldInfo lastField = type.Fields[type.Fields.Count - 1]; foreach (FieldInfo field in type.Fields) { // Writes something like: `[JsonProperty("foobar")] string foobar,` string ctorParameterName = this.GetCSharpCamelCaseName(field.MemberName); bool isLast = Object.ReferenceEquals(field, lastField); string comma = isLast ? "" : ","; // sw.Append(indentBodies); string attribute = config.GetCSharpJsonAttributeCode(field); if (attribute.Length > 0) { sw.Append(attribute); sw.Append(' '); } sw.AppendFormat("{0} {1}{2}{3}", /*0:*/ field.Type.GetTypeName(), /*1:*/ ctorParameterName, /*2:*/ comma, /*3:*/ Environment.NewLine); } } sw.AppendLine(indentMembers + ")"); // Constructor body: sw.AppendLine(indentMembers + "{"); foreach (FieldInfo field in type.Fields) { string ctorParameterName = this.GetCSharpCamelCaseName(field.MemberName); string classPropertyName = this.GetCSharpPascalCaseName(field.MemberName); sw.AppendFormat(indentBodies + "this.{0} = {1};{2}", /*0:*/ classPropertyName, /*1:*/ ctorParameterName, /*2:*/ Environment.NewLine); } sw.AppendLine(indentMembers + "}"); sw.AppendLine(); }
public void WriteClassMembers(IJsonClassGeneratorConfig config, StringBuilder sw, JsonType type, string indentMembers) { bool first = true; foreach (FieldInfo field in type.Fields) { string classPropertyName = this.GetCSharpPascalCaseName(field.MemberName); string propertyAttribute = config.GetCSharpJsonAttributeCode(field); if (!first && (propertyAttribute.Length > 0 || config.ExamplesInDocumentation)) { // If rendering examples/XML comments - or property attributes - then add a newline before the property for readability's sake (except if it's the first property in the class) sw.AppendLine(); } if (config.ExamplesInDocumentation) { sw.AppendFormat(indentMembers + "/// <summary>"); sw.AppendFormat(indentMembers + "/// Examples: " + field.GetExamplesText()); sw.AppendFormat(indentMembers + "/// </summary>"); sw.AppendLine(); } if (propertyAttribute.Length > 0) { sw.Append(indentMembers); sw.AppendLine(propertyAttribute); } if (config.UseFields) { sw.AppendFormat(indentMembers + "public {0}{1} {2};{3}", config.ImmutableClasses ? "readonly " : "", field.Type.GetTypeName(), classPropertyName, Environment.NewLine); } else if (config.ImmutableClasses) { if (field.Type.Type == JsonTypeEnum.Array) { sw.AppendFormat(indentMembers + "public IReadOnlyList<{0}> {1} {{ get; }}{2}", this.GetTypeName(field.Type.InternalType, config), classPropertyName, Environment.NewLine); } else { sw.AppendFormat(indentMembers + "public {0} {1} {{ get; }}{2}", field.Type.GetTypeName(), classPropertyName, Environment.NewLine); } } else { var getterSetterPart = "{ get; set; }"; if (config.NoSettersForCollections && (field.Type.IsCollectionType() && (config.ArrayAsList() && field.Type.Type == JsonTypeEnum.Array))) { getterSetterPart = "{ get; } = new " + field.Type.GetTypeName() + "();"; } sw.AppendFormat(indentMembers + "public {0} {1} {2}{3}", field.Type.GetTypeName(), classPropertyName, getterSetterPart, Environment.NewLine); } first = false; } }
public void WriteClassMembers(IJsonClassGeneratorConfig config, StringBuilder sw, JsonType type, string indentMembers) { bool first = true; foreach (FieldInfo field in type.Fields) { string classPropertyName = this.GetCSharpPascalCaseName(field.MemberName); string propertyAttribute = config.GetCSharpJsonAttributeCode(field); // If we are using record types and this is not the first iteration, add a comma and newline to the previous line // this is required because every line except the last should end with a comma if (config.OutputType == OutputTypes.ImmutableRecord && !first) { sw.AppendLine(","); } if (!first && ((propertyAttribute.Length > 0 && config.OutputType != OutputTypes.ImmutableRecord) || config.ExamplesInDocumentation)) { // If rendering examples/XML comments - or property attributes - then add a newline before the property for readability's sake (except if it's the first property in the class) // For record types, we want all members to be next to each other, unless when using examples sw.AppendLine(); } if (config.ExamplesInDocumentation) { sw.AppendFormat(indentMembers + "/// <summary>"); sw.AppendFormat(indentMembers + "/// Examples: " + field.GetExamplesText()); sw.AppendFormat(indentMembers + "/// </summary>"); sw.AppendLine(); } if (propertyAttribute.Length > 0) { sw.Append(indentMembers); sw.Append(propertyAttribute); if (config.OutputType != OutputTypes.ImmutableRecord) { sw.AppendLine(); } } // record types is not compatible with UseFields, so it comes first if (config.OutputType == OutputTypes.ImmutableRecord) { // NOTE: not adding newlines here, that happens at the start of the loop. We need this so we can lazily add commas at the end. if (field.Type.Type == JsonTypeEnum.Array) { // TODO: Respect config.CollectionType sw.AppendFormat(" IReadOnlyList<{0}> {1}", this.GetTypeName(field.Type.InternalType, config), classPropertyName); } else { sw.AppendFormat(" {0} {1}", field.Type.GetTypeName(), classPropertyName); } } else if (config.OutputType == OutputTypes.MutableClass) { if (config.MutableClasses.Members == OutputMembers.AsPublicFields) { // Render a field like `public int Foobar;`: bool useReadonlyModifier = config.OutputType == OutputTypes.ImmutableClass; sw.AppendFormat(indentMembers + "public {0}{1} {2};{3}", useReadonlyModifier ? "readonly " : "", field.Type.GetTypeName(), classPropertyName, Environment.NewLine); } else if (config.MutableClasses.Members == OutputMembers.AsProperties) { var getterSetterPart = "{ get; set; }"; bool addCollectionPropertyInitializer = config.MutableClasses.ReadOnlyCollectionProperties && field.Type.IsCollectionType() && config.CollectionType == OutputCollectionType.MutableList; if (addCollectionPropertyInitializer && field.Type.Type == JsonTypeEnum.Array) { getterSetterPart = "{ get; } = new " + field.Type.GetTypeName() + "();"; } sw.AppendFormat(indentMembers + "public {0} {1} {2}{3}", field.Type.GetTypeName(), classPropertyName, getterSetterPart, Environment.NewLine); } else { const String PATH = nameof(config) + "." + nameof(config.MutableClasses) + "." + nameof(config.MutableClasses.Members); const String MSG_FMT = "Invalid " + nameof(OutputMembers) + " enum value for " + PATH + ": {0}"; throw new InvalidOperationException(MSG_FMT); } } else if (config.OutputType == OutputTypes.ImmutableClass) { if (field.Type.Type == JsonTypeEnum.Array) { // TODO: Respect config.CollectionType sw.AppendFormat(indentMembers + "public IReadOnlyList<{0}> {1} {{ get; }}{2}", this.GetTypeName(field.Type.InternalType, config), classPropertyName, Environment.NewLine); } else { sw.AppendFormat(indentMembers + "public {0} {1} {{ get; }}{2}", field.Type.GetTypeName(), classPropertyName, Environment.NewLine); } } else { throw new InvalidOperationException("Invalid " + nameof(OutputTypes) + " value: " + config.OutputType); } first = false; } // emit a final newline if we're dealing with record types if (config.OutputType == OutputTypes.ImmutableRecord) { sw.AppendLine(); } }