diff --git a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts index e4bef052b8..006f095aea 100644 --- a/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts +++ b/src/generators/csharp/presets/NewtonsoftSerializerPreset.ts @@ -90,6 +90,13 @@ function renderDeserialize({ const corePropsRead = coreProps .map((prop) => { + // `const` properties are rendered as read-only (a `const` field or a + // getter-only property), so assigning to them here would not compile + // (CS0200/CS0131). The value is fixed by the schema, so there is nothing + // to deserialize into it. + if (prop.property.options.const) { + return ''; + } const propertyAccessor = pascalCase(prop.propertyName); let toValue = `jo["${prop.unconstrainedPropertyName}"].ToObject<${prop.property.type}>(serializer)`; if ( diff --git a/src/generators/csharp/renderers/ClassRenderer.ts b/src/generators/csharp/renderers/ClassRenderer.ts index 68fd06a193..65f7cb474f 100644 --- a/src/generators/csharp/renderers/ClassRenderer.ts +++ b/src/generators/csharp/renderers/ClassRenderer.ts @@ -119,7 +119,7 @@ export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset = { if (property.property.options.const) { return `public const ${property.property.type} ${pascalCase( property.propertyName - )} { ${getter} } = ${property.property.options.const.value};`; + )} = ${property.property.options.const.value};`; } const semiColon = nullablePropertyEnding !== '' ? ';' : ''; diff --git a/test/generators/csharp/CSharpGenerator.spec.ts b/test/generators/csharp/CSharpGenerator.spec.ts index 86f81aa603..4a4f56a857 100644 --- a/test/generators/csharp/CSharpGenerator.spec.ts +++ b/test/generators/csharp/CSharpGenerator.spec.ts @@ -170,6 +170,30 @@ describe('CSharpGenerator', () => { ]); }); + test('should generate a valid const property with autoImplementedProperties', async () => { + const autoImplementGenerator = new CSharpGenerator({ + modelType: 'class', + autoImplementedProperties: true + }); + const doc = { + $id: 'Event', + type: 'object', + properties: { + eventType: { type: 'string', const: 'OnEntryStarted' } + }, + required: ['eventType'] + }; + + const models = await autoImplementGenerator.generate(doc); + expect(models).toHaveLength(1); + // A C# `const` field cannot have `{ get; }` accessors, so it must be + // rendered as a plain const field assignment. + expect(models[0].result).toContain( + 'public const string EventType = "OnEntryStarted";' + ); + expect(models[0].result).not.toContain('public const string EventType {'); + }); + test('should render `enum` type', async () => { const doc = { $id: 'Things', diff --git a/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts b/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts index e7944e53d1..7694cc5087 100644 --- a/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts +++ b/test/generators/csharp/presets/NewtonsoftSerializerPreset.spec.ts @@ -47,4 +47,16 @@ describe('Newtonsoft JSON serializer preset', () => { expect(outputModels[1].result).toMatchSnapshot(); expect(outputModels[2].result).toMatchSnapshot(); }); + + test('should not assign to `const` properties in ReadJson', async () => { + const generator = new CSharpGenerator({ + presets: [CSHARP_NEWTONSOFT_SERIALIZER_PRESET] + }); + + const outputModels = await generator.generate(doc); + // `const` properties are rendered as read-only, so assigning to them in + // ReadJson would not compile (CS0200/CS0131). The deserializer must skip + // them. + expect(outputModels[0].result).not.toContain('value.ConstStringProp ='); + }); }); diff --git a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap index 2f3187edc1..5a01c3412b 100644 --- a/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/NewtonsoftSerializerPreset.spec.ts.snap @@ -75,9 +75,6 @@ public class TestConverter : JsonConverter } value.StringProp = jo[\\"string prop\\"].ToObject(serializer); -if(jo[\\"const string prop\\"] != null) { - value.ConstStringProp = jo[\\"const string prop\\"].ToObject(serializer); -} if(jo[\\"notRequiredStringProp\\"] != null) { value.NotRequiredStringProp = jo[\\"notRequiredStringProp\\"].ToObject(serializer); }