private IEnumerable <MemberDeclarationSyntax> GenerateUploadMembers(SourceFileContext ctx) { var uploadTyp = Typ.Nested(ctx.CurrentTyp, PascalCasedName + "MediaUpload"); var baseTypArgument1 = BodyTyp ?? Typ.Of <string>(); var baseTyp = _restMethod.Response is object ?Typ.Generic(Typ.Of(typeof(ResumableUpload <,>)), baseTypArgument1, ResponseTyp) : Typ.Generic(Typ.Of(typeof(ResumableUpload <>)), baseTypArgument1); var uploadCls = Class(Modifier.Public, uploadTyp, ctx.Type(baseTyp)) .WithXmlDoc(XmlDoc.Summary($"{PascalCasedName} media upload which supports resumable upload.")); var parameters = CreateParameterList(uploadTyp); var requiredParameters = parameters .TakeWhile(p => p.IsRequired) .Select(p => (param: p, decl: Parameter(ctx.Type(p.Typ), p.CodeParameterName))) .ToList(); var insertMethodParameters = new List <ParameterSyntax>(); if (BodyTyp is object) { insertMethodParameters.Add(Parameter(ctx.Type(BodyTyp), "body")); } insertMethodParameters.AddRange(requiredParameters.Select(pair => pair.decl)); var streamParam = Parameter(ctx.Type <Stream>(), "stream"); var contentTypeParam = Parameter(ctx.Type <string>(), "contentType"); insertMethodParameters.Add(streamParam); insertMethodParameters.Add(contentTypeParam); // This doc comment is common between the method and the constructor. var remarks = XmlDoc.Remarks("Considerations regarding ", streamParam, ":", XmlDoc.BulletListOfItemNodes( XmlDoc.Item("If ", streamParam, " is seekable, then the stream position will be reset to ", 0, " before reading commences. If ", streamParam, " is not seekable, then it will be read from its current position"), XmlDoc.Item("Caller is responsible for maintaining the ", streamParam, " open until the upload is completed"), XmlDoc.Item("Caller is responsible for closing the ", streamParam))); var methodDocComments = new List <DocumentationCommentTriviaSyntax> { XmlDoc.Summary(_restMethod.Description), remarks }; if (BodyTyp is object) { methodDocComments.Add(XmlDoc.Param(Parameter(ctx.Type(BodyTyp), "body"), "The body of the request.")); } methodDocComments.AddRange(requiredParameters.Select(pair => XmlDoc.Param(pair.decl, pair.param.Description))); methodDocComments.Add(XmlDoc.Param(streamParam, "The stream to upload. See remarks for further information.")); methodDocComments.Add(XmlDoc.Param(contentTypeParam, "The content type of the stream to upload.")); // We're taking it from the field in the parent type, but it becomes a parameter for the constructor... // So long as it appears as "service" we don't really mind. var serviceParam = Parameter(ctx.Type <IClientService>(), "service"); var ctorParameters = new List <ParameterSyntax> { serviceParam }; ctorParameters.AddRange(insertMethodParameters); var insertMethod = Method(Modifier.Public | Modifier.Virtual, ctx.Type(uploadTyp), PascalCasedName)(insertMethodParameters.ToArray()) .WithBlockBody(Return(New(ctx.Type(uploadTyp))(ctorParameters))) .WithXmlDoc(methodDocComments.ToArray()); using (ctx.InClass(uploadTyp)) { var baseInitializerArgs = new List <object> { serviceParam, ctx.Type <string>().Call(nameof(string.Format))("/{0}/{1}{2}", "upload", serviceParam.Access("BasePath"), _restMethod.Path), _restMethod.HttpMethod, streamParam, contentTypeParam }; var baseInitializer = BaseInitializer(baseInitializerArgs).WithAdditionalAnnotations(Annotations.LineBreakAnnotation); var assignments = requiredParameters.Select(p => Field(0, ctx.Type(p.param.Typ), p.param.PropertyName).Assign(p.decl)).ToList(); if (BodyTyp is object) { // The Body property is in the base class. var bodyProperty = Property(Modifier.Public, ctx.Type(BodyTyp), "Body"); assignments.Add(bodyProperty.Assign(Parameter(ctx.Type(BodyTyp), "body"))); } // The parameters to the constructor are the same as for the method. var uploadCtor = Ctor(Modifier.Public, uploadCls, baseInitializer)(ctorParameters.ToArray()) .WithBlockBody(assignments) .WithXmlDoc(XmlDoc.Summary($"Constructs a new {PascalCasedName} media upload instance."), remarks); uploadCls = uploadCls.AddMembers(Package.CreateParameterList(uploadTyp).SelectMany(p => p.GenerateDeclarations(ctx)).ToArray()); uploadCls = uploadCls.AddMembers(parameters.SelectMany(p => p.GenerateDeclarations(ctx)).ToArray()); uploadCls = uploadCls.AddMembers(uploadCtor); } yield return(insertMethod); yield return(uploadCls); }