diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs index 50f87680c53..66bac030238 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ModelProvider.cs @@ -53,7 +53,8 @@ protected override FormattableString BuildDescription() return description; } - private readonly bool _isMultiLevelDiscriminator; + private bool? _isMultiLevelDiscriminator; + private bool IsMultiLevelDiscriminator => _isMultiLevelDiscriminator ??= ComputeIsMultiLevelDiscriminator(); private readonly CSharpType _additionalBinaryDataPropsFieldType = typeof(IDictionary); private readonly CSharpType _additionalObjectPropsFieldType = typeof(IDictionary); @@ -75,7 +76,6 @@ public ModelProvider(InputModelType inputModel) : base(inputModel) { _inputModel = inputModel; _isDiscriminatedBaseType = inputModel.DiscriminatorProperty is not null && inputModel.DiscriminatorValue is null; - _isMultiLevelDiscriminator = ComputeIsMultiLevelDiscriminator(); _useObjectAdditionalProperties = new Lazy(ShouldUseObjectAdditionalProperties); } @@ -188,6 +188,7 @@ public override void Reset() _additionalPropertyFields = null; _additionalPropertyProperties = null; _fullConstructor = null; + _isMultiLevelDiscriminator = null; } protected FieldProvider? RawDataField @@ -765,7 +766,7 @@ protected internal override ConstructorProvider[] BuildConstructors() } // For multi-level discriminators, add one additional private protected constructor - if (_isMultiLevelDiscriminator) + if (IsMultiLevelDiscriminator) { var protectedConstructor = BuildProtectedInheritanceConstructor(); constructors.Add(protectedConstructor); @@ -945,7 +946,7 @@ private IEnumerable GetAllBaseFieldsForConstructorInitialization( ? baseParameters : baseParameters.Where(p => p.Property is null - || (!overriddenProperties.Contains(p.Property!) && (!p.Property.IsDiscriminator || !isInitializationConstructor || (includeDiscriminatorParameter && _isMultiLevelDiscriminator))))); + || (!overriddenProperties.Contains(p.Property!) && (!p.Property.IsDiscriminator || !isInitializationConstructor || (includeDiscriminatorParameter && IsMultiLevelDiscriminator))))); // construct the initializer using the parameters from base signature ConstructorInitializer? constructorInitializer = null; @@ -954,7 +955,7 @@ p.Property is null if (baseParameters.Count > 0) { // Check if we should call multi-level discriminator constructor - if (isInitializationConstructor && (_isMultiLevelDiscriminator || BaseModelProvider._isMultiLevelDiscriminator)) + if (isInitializationConstructor && (IsMultiLevelDiscriminator || BaseModelProvider.IsMultiLevelDiscriminator)) { var baseDiscriminatorParam = baseParameters.FirstOrDefault(p => p.Property?.IsDiscriminator == true); var hasDiscriminatorProperty = BaseModelProvider.CanonicalView.Properties.Any(p => p.IsDiscriminator); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs index 88ab6c206b8..dcad924214f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelProviderTests.cs @@ -1646,6 +1646,30 @@ public DerivedModelProviderReadingOwnField(InputModelType inputModel) : base(inp } } + [Test] + public void DerivedModelProviderConstructionDoesNotForceNameEvaluation() + { + var inputModel = InputFactory.Model("MockInputModel", access: "public"); + MockHelpers.LoadMockGenerator(inputModelTypes: [inputModel]); + + DerivedModelProviderReadingOwnName? provider = null; + Assert.DoesNotThrow(() => provider = new DerivedModelProviderReadingOwnName(inputModel, "ProjectedModel")); + Assert.AreEqual("ProjectedModel", provider!.Name); + } + + private sealed class DerivedModelProviderReadingOwnName : ModelProvider + { + private readonly string? _derivedName; + + public DerivedModelProviderReadingOwnName(InputModelType inputModel, string derivedName) : base(inputModel) + { + _derivedName = derivedName; + } + + protected override string BuildName() + => _derivedName ?? throw new InvalidOperationException("The derived provider has not finished construction."); + } + // Regression for the second virtual-call-in-ctor offender: ModelProvider..ctor used to // eagerly compute DiscriminatorValueExpression, which read BaseModelProvider and thus // virtually dispatched BuildBaseType()/BuildBaseModel() onto a partially-constructed