in src/AutoRest.CSharp/Common/Output/Models/Types/ModelFactoryTypeProvider.cs [208:307]
private Method CreateMethod(SerializableObjectType model)
{
var ctor = model.SerializationConstructor;
var ctorToCall = ctor;
var discriminator = model.Discriminator;
if (model.Declaration.IsAbstract && discriminator != null)
{
// the model factory entry method `RequiresModelFactory` makes sure this: if this model is abstract, the discriminator must not be null
ctorToCall = discriminator.DefaultObjectType.SerializationConstructor;
}
var methodParameters = new List<Parameter>(ctor.Signature.Parameters.Count);
var methodArguments = new List<ValueExpression>(ctor.Signature.Parameters.Count);
foreach (var ctorParameter in ctorToCall.Signature.Parameters)
{
var property = ctorToCall.FindPropertyInitializedByParameter(ctorParameter);
if (property == null)
{
// if the property is not found, in order not to introduce compilation errors, we need to add a `default` into the argument list
methodArguments.Add(new PositionalParameterReference(ctorParameter.Name, Default));
continue;
}
if (ctorParameter.IsRawData)
{
// we do not want to include the raw data as a parameter of the model factory entry method, therefore here we skip the parameter, and use empty dictionary as argument
methodArguments.Add(new PositionalParameterReference(ctorParameter.Name, Null));
continue;
}
if (property.FlattenedProperty != null)
property = property.FlattenedProperty;
var parameterName = property.Declaration.Name.ToVariableName();
var inputType = property.Declaration.Type;
// check if the property is the discriminator, but skip the check if the configuration is on for HLC only
if (discriminator != null && discriminator.Property == property && !Configuration.ModelFactoryForHlc.Contains(model.Declaration.Name))
{
if (discriminator.Value is { } value)
{
// this is a derived class, we do not add this parameter to the method, but we need an argument for the invocation
methodArguments.Add(new ConstantExpression(value));
continue;
}
// this class is the base in a discriminated set
switch (inputType)
{
case { IsFrameworkType: false, Implementation: EnumType { IsExtensible: true } extensibleEnum }:
inputType = extensibleEnum.ValueType;
break;
case { IsFrameworkType: false, Implementation: EnumType { IsExtensible: false } }:
// we skip the parameter if the discriminator is a sealed choice because we can never pass in a "Unknown" value.
// but we still need to add it to the method argument list as a `default`
methodArguments.Add(Default);
continue;
default:
break;
}
}
inputType = inputType.InputType;
if (!inputType.IsValueType)
{
inputType = inputType.WithNullable(true);
}
var parameter = ctorParameter with
{
Name = parameterName,
Type = inputType,
DefaultValue = Constant.Default(inputType),
Initializer = inputType.GetParameterInitializer(ctorParameter.DefaultValue)
};
methodParameters.Add(parameter);
var expression = BuildPropertyAssignmentExpression(parameter, property).GetConversion(parameter.Type, ctorParameter.Type);
methodArguments.Add(expression);
}
FormattableString returnDescription = $"A new {model.Type:C} instance for mocking.";
var signature = new MethodSignature(
ctor.Signature.Name,
ctor.Signature.Summary,
ctor.Signature.Description,
MethodSignatureModifiers.Public | MethodSignatureModifiers.Static,
model.Type,
returnDescription,
methodParameters);
var methodBody = new MethodBodyStatement[]
{
// write the initializers and validations
new ParameterValidationBlock(methodParameters, true),
Return(New.Instance(ctorToCall.Signature, methodArguments))
};
return new(signature, methodBody);
}