public Task <ClassDeclarationSyntax> GenerateClientClass(SemanticModel semanticModel, SyntaxGenerator gen, INamedTypeSymbol proxyInterface, string name, Accessibility accessibility, bool includeCancellableAsyncMethods, bool suppressWarningComments, MemberAccessibility constructorAccessibility, bool withInternalProxy) { if (name == null) { if (proxyInterface.Name.StartsWith("I")) { name = proxyInterface.Name.Substring(1); } if (name.EndsWith("Proxy")) { name = name.Substring(0, name.Length - "Proxy".Length); } if (!name.EndsWith("Client")) { name = name + "Client"; } } SyntaxNode targetClass = gen.ClassDeclaration(name, baseType: gen.TypeExpression(semanticModel.Compilation.RequireType <MarshalByRefObject>()), accessibility: accessibility, modifiers: DeclarationModifiers.Sealed); targetClass = gen.AddWarningCommentIf(!suppressWarningComments, targetClass); targetClass = gen.AddInterfaceType(targetClass, gen.TypeExpression(semanticModel.Compilation.GetSpecialType(SpecialType.System_IDisposable))); targetClass = gen.AddInterfaceType(targetClass, gen.TypeExpression(proxyInterface)); IEnumerable <IMethodSymbol> methods = GetOperationContractMethods(semanticModel.Compilation, proxyInterface).ToArray(); GenerationNameTable nameTable = new GenerationNameTable(methods.Select(m => m.Name).Concat(new[] { name })); #region Private Fields // ==> private IProxy m_cachedProxy; SyntaxNode cachedProxyField = gen.FieldDeclaration(nameTable[MemberNames.CachedProxyField], gen.TypeExpression(proxyInterface), Accessibility.Private, DeclarationModifiers.None) .PrependLeadingTrivia(gen.CreateRegionTrivia("Private Fields")); targetClass = gen.AddMembers(targetClass, cachedProxyField); // ==> private readonly Func<IProxy> m_proxyFactory; SyntaxNode proxyFactoryTypeExpression = gen.TypeExpression(semanticModel.Compilation.RequireTypeByMetadataName("System.Func`1").Construct(proxyInterface)); targetClass = gen.AddMembers(targetClass, gen.FieldDeclaration(nameTable[MemberNames.ProxyFactoryField], proxyFactoryTypeExpression, Accessibility.Private, DeclarationModifiers.ReadOnly) .AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia()); #endregion #region Constructors // Constructor SyntaxNode constructor = gen.ConstructorDeclaration( parameters: new[] { gen.ParameterDeclaration("proxyFactory", proxyFactoryTypeExpression) }, accessibility: withInternalProxy?Accessibility.Private: ToAccessibility(constructorAccessibility) ); constructor = gen.AddWarningCommentIf(!suppressWarningComments, constructor); constructor = constructor.PrependLeadingTrivia(gen.CreateRegionTrivia("Constructors")); constructor = gen.WithStatements(constructor, new[] { // ==> if (proxyFactory == null) // ==> throw new System.ArgumentNullException("proxyFactory"); gen.ThrowIfNullStatement("proxyFactory"), // ==> m_proxyFactory = proxyFactory gen.AssignmentStatement( gen.MemberAccessExpression( gen.ThisExpression(), gen.IdentifierName(nameTable[MemberNames.ProxyFactoryField])), gen.IdentifierName("proxyFactory") ) } ).AddNewLineTrivia(); if (!withInternalProxy) { constructor = constructor.AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia(); } targetClass = gen.AddMembers(targetClass, constructor); ClassDeclarationSyntax proxyClass = null; if (withInternalProxy) { IEnumerable <IMethodSymbol> ctors; proxyClass = GenerateProxyClass(semanticModel, gen, proxyInterface, nameTable[MemberNames.ProxyClass], Accessibility.Private, suppressWarningComments, MemberAccessibility.Public, out ctors) .PrependLeadingTrivia(gen.CreateRegionTrivia("Proxy Class").Insert(0, gen.NewLine())) .AddTrailingTrivia(gen.CreateEndRegionTrivia()); // Generate one constructor for each of the proxy's constructors. foreach (var ctorEntry in ctors.AsSmartEnumerable()) { var ctor = ctorEntry.Value; var targetCtor = gen.ConstructorDeclaration(ctor); var lambda = gen.ValueReturningLambdaExpression( gen.ObjectCreationExpression(gen.IdentifierName(gen.GetName(proxyClass)), ctor.Parameters.Select(p => gen.IdentifierName(p.Name))) ); targetCtor = gen.WithThisConstructorInitializer(targetCtor, new[] { lambda }); targetCtor = gen.AddWarningCommentIf(!suppressWarningComments, targetCtor); targetCtor = gen.WithAccessibility(targetCtor, ToAccessibility(constructorAccessibility)); if (ctorEntry.IsLast) { targetCtor = targetCtor.AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia(); } targetClass = gen.AddMembers(targetClass, targetCtor.AddNewLineTrivia()); } } #endregion #region Operation Contract Methods // ==> catch // ==> { // ==> this.CloseProxy(false); // ==> throw; // ==> } var catchAndCloseProxyStatement = gen.CatchClause(new SyntaxNode[] { // ==> this.CloseProxy(false); gen.ExpressionStatement( gen.InvocationExpression( gen.MemberAccessExpression( gen.ThisExpression(), nameTable[MemberNames.CloseProxyMethod] ), gen.FalseLiteralExpression() ) ), // throw; gen.ThrowStatement() }); foreach (var sourceMethodEntry in methods.AsSmartEnumerable()) { var sourceMethod = sourceMethodEntry.Value; using (nameTable.PushScope(sourceMethod.Parameters.Select(p => p.Name))) { bool isAsync = ReturnsTask(semanticModel.Compilation, sourceMethod); bool isVoid = sourceMethod.ReturnType.SpecialType == SpecialType.System_Void || sourceMethod.ReturnType.Equals(semanticModel.Compilation.RequireType <Task>()); SyntaxNode targetMethod = gen.MethodDeclaration(sourceMethod); if (sourceMethodEntry.IsFirst) { targetMethod = targetMethod.PrependLeadingTrivia(gen.CreateRegionTrivia("Contract Methods")).AddLeadingTrivia(gen.NewLine()); } targetMethod = gen.AddWarningCommentIf(!suppressWarningComments, targetMethod); targetMethod = gen.WithModifiers(targetMethod, isAsync ? DeclarationModifiers.Async : DeclarationModifiers.None); targetMethod = gen.WithStatements(targetMethod, new SyntaxNode[] { // ==> try { gen.TryCatchStatement(new SyntaxNode[] { CreateProxyVaraibleDeclaration(gen, nameTable, isAsync), CreateProxyInvocationStatement(semanticModel.Compilation, gen, nameTable, sourceMethod) }, new SyntaxNode[] { catchAndCloseProxyStatement } ) }); targetMethod = targetMethod.AddNewLineTrivia(); if (sourceMethodEntry.IsLast && !(isAsync && includeCancellableAsyncMethods)) { targetMethod = targetMethod.AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia(); } targetClass = gen.AddMembers(targetClass, targetMethod); if (isAsync && includeCancellableAsyncMethods) { targetMethod = gen.MethodDeclaration(sourceMethod); targetMethod = gen.AddParameters(targetMethod, new[] { gen.ParameterDeclaration(nameTable[MemberNames.CancellationTokenParameter], gen.TypeExpression(semanticModel.Compilation.RequireType <CancellationToken>())) }); targetMethod = gen.WithModifiers(targetMethod, isAsync ? DeclarationModifiers.Async : DeclarationModifiers.None); targetMethod = gen.WithStatements(targetMethod, new SyntaxNode[] { // ==> try { gen.TryCatchStatement(new SyntaxNode[] { CreateProxyVaraibleDeclaration(gen, nameTable, isAsync), CreateCancellableProxyInvocationStatement(semanticModel.Compilation, gen, nameTable, sourceMethod) }, new SyntaxNode[] { catchAndCloseProxyStatement } ) }); targetMethod = gen.AddWarningCommentIf(!suppressWarningComments, targetMethod.AddNewLineTrivia()); if (sourceMethodEntry.IsLast) { targetMethod = targetMethod.AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia(); } targetClass = gen.AddMembers(targetClass, targetMethod); } } } #endregion #region Internal Methods targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateGetProxyMethod(semanticModel.Compilation, gen, proxyInterface, nameTable, false).AddLeadingTrivia(gen.CreateRegionTrivia("Private Methods")).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateGetProxyMethod(semanticModel.Compilation, gen, proxyInterface, nameTable, true).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateStaticCloseProxyMethod(semanticModel.Compilation, gen, nameTable, false).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateStaticCloseProxyMethod(semanticModel.Compilation, gen, nameTable, true).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateCloseProxyMethod(semanticModel.Compilation, gen, nameTable, false).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateCloseProxyMethod(semanticModel.Compilation, gen, nameTable, true).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateEnsureProxyMethod(semanticModel.Compilation, gen, nameTable, false).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, gen.AddWarningCommentIf(!suppressWarningComments, CreateEnsureProxyMethod(semanticModel.Compilation, gen, nameTable, true).AddTrailingTrivia(gen.CreateEndRegionTrivia()).AddNewLineTrivia())); targetClass = gen.AddMembers(targetClass, CreateDisposeMethods(semanticModel.Compilation, gen, nameTable, suppressWarningComments)); if (withInternalProxy) { targetClass = gen.AddMembers(targetClass, proxyClass); } #endregion targetClass = AddGeneratedCodeAttribute(gen, targetClass); return(Task.FromResult((ClassDeclarationSyntax)targetClass)); }