in src/JetBrains.Space.Generator/CodeGeneration/CSharp/Generators/CSharpApiModelDtoGenerator.cs [202:329]
private string GenerateDtoFieldDefinition(string dtoId, string typeNameForDto, ApiField apiField)
{
var indent = new Indent();
var builder = new CSharpBuilder();
var propertyNameForField = apiField.ToCSharpPropertyName(typeNameForDto);
var backingFieldNameForField = apiField.ToCSharpBackingFieldName();
// Backing field
builder.Append($"{indent}private PropertyValue<");
builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
if (apiField.Type.Nullable)
{
builder.Append('?');
}
if (!apiField.Type.Nullable && apiField.RequiresAddedNullability())
{
builder.Append('?');
}
builder.Append("> ");
builder.Append($"{backingFieldNameForField} = new PropertyValue<");
builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
if (apiField.Type.Nullable)
{
builder.Append('?');
}
if (!apiField.Type.Nullable && apiField.RequiresAddedNullability())
{
builder.Append('?');
}
// For non-nullable List<> and Dictionary<>, make sure the field is initialized.
// We do this by setting a temporary default value for this pass.
var overrideDefaultValue = !apiField.Type.Nullable && apiField.DefaultValue == null;
if (overrideDefaultValue)
{
// REVIEW: This is a mutation, might be good to consider making this immutable.
apiField.DefaultValue = apiField.Type switch
{
ApiFieldType.Array => new ApiDefaultValue.Collection(),
ApiFieldType.Map => new ApiDefaultValue.Map(),
_ => apiField.DefaultValue
};
}
var initialValueForAssignment = apiField.ToCSharpDefaultValueForAssignment(_codeGenerationContext);
if (initialValueForAssignment != null)
{
builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}), \"{apiField.Name}\", {initialValueForAssignment});");
}
else
{
builder.AppendLine($">(nameof({typeNameForDto}), nameof({propertyNameForField}), \"{apiField.Name}\");");
}
builder.AppendLine($"{indent}");
// Restore null default value
if (overrideDefaultValue)
{
apiField.DefaultValue = null;
}
// Property
ApiDocumentationUtilities.RenderCSharpDocumentation(apiField.Description, apiField.Experimental, output =>
{
builder.Append(indent.Wrap(output));
});
if (!apiField.Optional && !apiField.Type.Nullable)
{
builder.AppendLine($"{indent}[Required]");
}
if (apiField.Optional && (apiField.Type.Nullable || apiField.RequiresAddedNullability()) && _codeGenerationContext.IsRequestBodyDto(dtoId))
{
// REMARK: This only works well in .NET6+.
// Since .NET3.1 will go out of support relatively soon (December 3, 2022 - https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core),
// we decided to only add optional request body properties in supported .NET versions.
builder.AppendLine($"#if NET6_0_OR_GREATER");
builder.AppendLine($"{indent}[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]");
builder.AppendLine($"#endif");
}
if (apiField.Deprecation != null)
{
builder.AppendLine($"{indent}{apiField.Deprecation.ToCSharpDeprecation()}");
}
else if (apiField.Experimental != null && FeatureFlags.GenerateExperimentalAnnotations)
{
builder.AppendLine($"{indent}{apiField.Experimental.ToCSharpExperimental()}");
}
builder.AppendLine($"{indent}[JsonPropertyName(\"{apiField.Name}\")]");
if (apiField.Type is ApiFieldType.Primitive apiFieldTypePrimitive)
{
var csharpType = apiFieldTypePrimitive.ToCSharpPrimitiveType();
if (csharpType.JsonConverter != null)
{
builder.AppendLine($"{indent}[JsonConverter(typeof({csharpType.JsonConverter.Name}))]");
}
}
builder.Append($"{indent}public ");
builder.Append(apiField.Type.ToCSharpType(_codeGenerationContext));
if (apiField.Type.Nullable)
{
builder.Append('?');
}
if (!apiField.Type.Nullable && apiField.RequiresAddedNullability())
{
builder.Append('?');
}
builder.Append(" ");
builder.AppendLine($"{indent}{propertyNameForField}");
builder.AppendLine($"{indent}{{");
indent.Increment();
builder.AppendLine($"{indent}get => {backingFieldNameForField}.GetValue({nameof(IPropagatePropertyAccessPath.InlineErrors)});");
builder.AppendLine($"{indent}set => {backingFieldNameForField}.SetValue(value);");
indent.Decrement();
builder.AppendLine($"{indent}}}");
return builder.ToString();
}