Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Description / ClientClassGenerator.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.ServiceModel.Description
6 {
7     using System;
8     using System.CodeDom;
9     using System.Collections.ObjectModel;
10     using System.ComponentModel;
11     using System.Globalization;
12     using System.Reflection;
13     using System.Runtime;
14     using System.ServiceModel;
15     using System.ServiceModel.Channels;
16     using System.Threading;
17
18     class ClientClassGenerator : IServiceContractGenerationExtension
19     {
20         bool tryAddHelperMethod = false;
21         bool generateEventAsyncMethods = false;
22
23         internal ClientClassGenerator(bool tryAddHelperMethod)
24             : this(tryAddHelperMethod, false)
25         {
26         }
27
28         internal ClientClassGenerator(bool tryAddHelperMethod, bool generateEventAsyncMethods)
29         {
30             this.tryAddHelperMethod = tryAddHelperMethod;
31             this.generateEventAsyncMethods = generateEventAsyncMethods;
32         }
33
34         static Type clientBaseType = typeof(ClientBase<>);
35         static Type duplexClientBaseType = typeof(DuplexClientBase<>);
36         static Type instanceContextType = typeof(InstanceContext);
37         static Type objectType = typeof(object);
38         static Type objectArrayType = typeof(object[]);
39         static Type exceptionType = typeof(Exception);
40         static Type boolType = typeof(bool);
41         static Type stringType = typeof(string);
42         static Type endpointAddressType = typeof(EndpointAddress);
43         static Type uriType = typeof(Uri);
44         static Type bindingType = typeof(Binding);
45         static Type sendOrPostCallbackType = typeof(SendOrPostCallback);
46         static Type asyncCompletedEventArgsType = typeof(AsyncCompletedEventArgs);
47         static Type eventHandlerType = typeof(EventHandler<>);
48         static Type voidType = typeof(void);
49         static Type asyncResultType = typeof(IAsyncResult);
50         static Type asyncCallbackType = typeof(AsyncCallback);
51         
52         static CodeTypeReference voidTypeRef = new CodeTypeReference(typeof(void));
53         static CodeTypeReference asyncResultTypeRef = new CodeTypeReference(typeof(IAsyncResult));
54
55         static string inputInstanceName = "callbackInstance";
56         static string invokeAsyncCompletedEventArgsTypeName = "InvokeAsyncCompletedEventArgs";
57         static string invokeAsyncMethodName = "InvokeAsync";
58         static string raiseExceptionIfNecessaryMethodName = "RaiseExceptionIfNecessary";
59         static string beginOperationDelegateTypeName = "BeginOperationDelegate";
60         static string endOperationDelegateTypeName = "EndOperationDelegate";
61         static string getDefaultValueForInitializationMethodName = "GetDefaultValueForInitialization";
62
63         // IMPORTANT: this table tracks the set of .ctors in ClientBase and DuplexClientBase. 
64         // This table must be kept in sync
65         // for DuplexClientBase, the initial InstanceContext param is assumed; ctor overloads must match between ClientBase and DuplexClientBase
66         static Type[][] ClientCtorParamTypes = new Type[][]
67             {
68                 new Type[] { },
69                 new Type[] { stringType, },
70                 new Type[] { stringType, stringType, },
71                 new Type[] { stringType, endpointAddressType, },
72                 new Type[] { bindingType, endpointAddressType, },
73             };
74
75         static string[][] ClientCtorParamNames = new string[][]
76             {
77                 new string[] { },
78                 new string[] { "endpointConfigurationName", },
79                 new string[] { "endpointConfigurationName", "remoteAddress", },
80                 new string[] { "endpointConfigurationName", "remoteAddress", },
81                 new string[] { "binding", "remoteAddress", },
82             };
83
84         static Type[] EventArgsCtorParamTypes = new Type[] 
85         { 
86             objectArrayType, 
87             exceptionType, 
88             boolType, 
89             objectType 
90         };
91
92         static string[] EventArgsCtorParamNames = new string[] 
93         {
94             "results",
95             "exception",
96             "cancelled",
97             "userState"
98         };
99
100         static string[] EventArgsPropertyNames = new string[]
101         {
102             "Results",
103             "Error",
104             "Cancelled",
105             "UserState"
106         };
107
108 #if DEBUG
109         static BindingFlags ctorBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
110         static string DebugCheckTable_errorString = "Client code generation table out of sync with ClientBase and DuplexClientBase ctors. Please investigate.";
111
112         // check the table against what we would get from reflection
113         static void DebugCheckTable()
114         {
115             Fx.Assert(ClientCtorParamNames.Length == ClientCtorParamTypes.Length, DebugCheckTable_errorString);
116
117             for (int i = 0; i < ClientCtorParamTypes.Length; i++)
118             {
119                 DebugCheckTable_ValidateCtor(clientBaseType.GetConstructor(ctorBindingFlags, null, ClientCtorParamTypes[i], null), ClientCtorParamNames[i]);
120
121                 Type[] duplexCtorTypes1 = DebugCheckTable_InsertAtStart(ClientCtorParamTypes[i], objectType);
122                 Type[] duplexCtorTypes2 = DebugCheckTable_InsertAtStart(ClientCtorParamTypes[i], instanceContextType);
123                 string[] duplexCtorNames = DebugCheckTable_InsertAtStart(ClientCtorParamNames[i], inputInstanceName);
124
125                 DebugCheckTable_ValidateCtor(duplexClientBaseType.GetConstructor(ctorBindingFlags, null, duplexCtorTypes1, null), duplexCtorNames);
126                 DebugCheckTable_ValidateCtor(duplexClientBaseType.GetConstructor(ctorBindingFlags, null, duplexCtorTypes2, null), duplexCtorNames);
127             }
128
129             // ClientBase<> has extra InstanceContext overloads that we do not call directly from the generated code, but which we 
130             // need to account for in this assert
131             Fx.Assert(clientBaseType.GetConstructors(ctorBindingFlags).Length == ClientCtorParamTypes.Length * 2, DebugCheckTable_errorString);
132
133             // DuplexClientBase<> also has extra object/InstanceContext overloads (but we call these)
134             Fx.Assert(duplexClientBaseType.GetConstructors(ctorBindingFlags).Length == ClientCtorParamTypes.Length * 2, DebugCheckTable_errorString);
135         }
136
137         static T[] DebugCheckTable_InsertAtStart<T>(T[] arr, T item)
138         {
139             T[] newArr = new T[arr.Length + 1];
140             newArr[0] = item;
141             Array.Copy(arr, 0, newArr, 1, arr.Length);
142             return newArr;
143         }
144
145         static void DebugCheckTable_ValidateCtor(ConstructorInfo ctor, string[] paramNames)
146         {
147             Fx.Assert(ctor != null, DebugCheckTable_errorString);
148
149             ParameterInfo[] parameters = ctor.GetParameters();
150             Fx.Assert(parameters.Length == paramNames.Length, DebugCheckTable_errorString);
151             for (int i = 0; i < paramNames.Length; i++)
152             {
153                 Fx.Assert(parameters[i].Name == paramNames[i], DebugCheckTable_errorString);
154             }
155         }
156 #endif
157
158         void IServiceContractGenerationExtension.GenerateContract(ServiceContractGenerationContext context)
159         {
160 #if DEBUG
161             // DebugCheckTable();
162 #endif
163             CodeTypeDeclaration clientType = context.TypeFactory.CreateClassType();
164             // Have to make sure that client name does not match any methods: member names can not be the same as their enclosing type (CSharp only)
165             clientType.Name = NamingHelper.GetUniqueName(GetClientClassName(context.ContractType.Name), DoesMethodNameExist, context.Operations);
166             CodeTypeReference contractTypeRef = context.ContractTypeReference;
167             if (context.DuplexCallbackType == null)
168                 clientType.BaseTypes.Add(new CodeTypeReference(context.ServiceContractGenerator.GetCodeTypeReference(typeof(ClientBase<>)).BaseType, context.ContractTypeReference));
169             else
170                 clientType.BaseTypes.Add(new CodeTypeReference(context.ServiceContractGenerator.GetCodeTypeReference(typeof(DuplexClientBase<>)).BaseType, context.ContractTypeReference));
171
172             clientType.BaseTypes.Add(context.ContractTypeReference);
173
174             if (!(ClientCtorParamNames.Length == ClientCtorParamTypes.Length))
175             {
176                 Fx.Assert("Invalid client generation constructor table initialization");
177                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid client generation constructor table initialization")));
178             }
179
180             for (int i = 0; i < ClientCtorParamNames.Length; i++)
181             {
182                 if (!(ClientCtorParamNames[i].Length == ClientCtorParamTypes[i].Length))
183                 {
184                     Fx.Assert("Invalid client generation constructor table initialization");
185                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid client generation constructor table initialization")));
186                 }
187
188                 CodeConstructor ctor = new CodeConstructor();
189                 ctor.Attributes = MemberAttributes.Public;
190                 if (context.DuplexCallbackType != null)
191                 {
192                     ctor.Parameters.Add(new CodeParameterDeclarationExpression(typeof(InstanceContext), inputInstanceName));
193                     ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(inputInstanceName));
194                 }
195                 for (int j = 0; j < ClientCtorParamNames[i].Length; j++)
196                 {
197                     ctor.Parameters.Add(new CodeParameterDeclarationExpression(ClientCtorParamTypes[i][j], ClientCtorParamNames[i][j]));
198                     ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(ClientCtorParamNames[i][j]));
199                 }
200                 clientType.Members.Add(ctor);
201             }
202
203             foreach (OperationContractGenerationContext operationContext in context.Operations)
204             {
205                 // Note that we generate all the client-side methods, even inherited ones.
206                 if (operationContext.Operation.IsServerInitiated()) continue;
207                 CodeTypeReference declaringContractTypeRef = operationContext.DeclaringTypeReference;
208                 GenerateClientClassMethod(clientType, contractTypeRef, operationContext.SyncMethod, this.tryAddHelperMethod, declaringContractTypeRef);
209
210                 if (operationContext.IsAsync)
211                 {
212                     CodeMemberMethod beginMethod = GenerateClientClassMethod(clientType, contractTypeRef, operationContext.BeginMethod, this.tryAddHelperMethod, declaringContractTypeRef);
213                     CodeMemberMethod endMethod = GenerateClientClassMethod(clientType, contractTypeRef, operationContext.EndMethod, this.tryAddHelperMethod, declaringContractTypeRef);
214
215                     if (this.generateEventAsyncMethods)
216                     {
217                         GenerateEventAsyncMethods(context, clientType, operationContext.SyncMethod.Name, beginMethod, endMethod);
218                     }
219                 }
220
221                 if (operationContext.IsTask)
222                 {
223                     GenerateClientClassMethod(clientType, contractTypeRef, operationContext.TaskMethod, !operationContext.Operation.HasOutputParameters && this.tryAddHelperMethod, declaringContractTypeRef);
224                 }
225             }
226
227             context.Namespace.Types.Add(clientType);
228             context.ClientType = clientType;
229             context.ClientTypeReference = ServiceContractGenerator.NamespaceHelper.GetCodeTypeReference(context.Namespace, clientType);
230         }
231
232         static CodeMemberMethod GenerateClientClassMethod(CodeTypeDeclaration clientType, CodeTypeReference contractTypeRef, CodeMemberMethod method, bool addHelperMethod, CodeTypeReference declaringContractTypeRef)
233         {
234             CodeMemberMethod methodImpl = GetImplementationOfMethod(contractTypeRef, method);
235             AddMethodImpl(methodImpl);
236             int methodPosition = clientType.Members.Add(methodImpl);
237             CodeMemberMethod helperMethod = null;
238
239             if (addHelperMethod)
240             {
241                 helperMethod = GenerateHelperMethod(declaringContractTypeRef, methodImpl);
242                 if (helperMethod != null)
243                 {
244                     clientType.Members[methodPosition].CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));
245                     clientType.Members.Add(helperMethod);
246                 }
247             }
248
249             return (helperMethod != null) ? helperMethod : methodImpl;
250         }
251
252         internal static CodeAttributeDeclaration CreateEditorBrowsableAttribute(EditorBrowsableState editorBrowsableState)
253         {
254             CodeAttributeDeclaration browsableAttribute = new CodeAttributeDeclaration(new CodeTypeReference(typeof(EditorBrowsableAttribute)));
255             CodeTypeReferenceExpression browsableAttributeState = new CodeTypeReferenceExpression(typeof(EditorBrowsableState));
256             CodeAttributeArgument browsableAttributeValue = new CodeAttributeArgument(new CodeFieldReferenceExpression(browsableAttributeState, editorBrowsableState.ToString()));
257             browsableAttribute.Arguments.Add(browsableAttributeValue);
258
259             return browsableAttribute;
260         }
261
262         private static CodeMemberMethod GenerateHelperMethod(CodeTypeReference ifaceType, CodeMemberMethod method)
263         {
264             CodeMemberMethod helperMethod = new CodeMemberMethod();
265             helperMethod.Name = method.Name;
266             helperMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
267             CodeMethodInvokeExpression invokeMethod = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeCastExpression(ifaceType, new CodeThisReferenceExpression()), method.Name));
268             bool hasTypedMessage = false;
269             foreach (CodeParameterDeclarationExpression param in method.Parameters)
270             {
271                 CodeTypeDeclaration paramTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(param.Type);
272                 if (paramTypeDecl != null)
273                 {
274                     hasTypedMessage = true;
275                     CodeVariableReferenceExpression inValue = new CodeVariableReferenceExpression("inValue");
276                     helperMethod.Statements.Add(new CodeVariableDeclarationStatement(param.Type, inValue.VariableName, new CodeObjectCreateExpression(param.Type)));
277                     invokeMethod.Parameters.Add(inValue);
278                     GenerateParameters(helperMethod, paramTypeDecl, inValue, FieldDirection.In);
279                 }
280                 else
281                 {
282                     helperMethod.Parameters.Add(new CodeParameterDeclarationExpression(param.Type, param.Name));
283                     invokeMethod.Parameters.Add(new CodeArgumentReferenceExpression(param.Name));
284                 }
285             }
286             if (method.ReturnType.BaseType == voidTypeRef.BaseType)
287                 helperMethod.Statements.Add(invokeMethod);
288             else
289             {
290                 CodeTypeDeclaration returnTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(method.ReturnType);
291                 if (returnTypeDecl != null)
292                 {
293                     hasTypedMessage = true;
294                     CodeVariableReferenceExpression outVar = new CodeVariableReferenceExpression("retVal");
295
296                     helperMethod.Statements.Add(new CodeVariableDeclarationStatement(method.ReturnType, outVar.VariableName, invokeMethod));
297                     CodeMethodReturnStatement returnStatement = GenerateParameters(helperMethod, returnTypeDecl, outVar, FieldDirection.Out);
298                     if (returnStatement != null)
299                         helperMethod.Statements.Add(returnStatement);
300                 }
301                 else
302                 {
303                     helperMethod.Statements.Add(new CodeMethodReturnStatement(invokeMethod));
304                     helperMethod.ReturnType = method.ReturnType;
305                 }
306             }
307             if (hasTypedMessage)
308                 method.PrivateImplementationType = ifaceType;
309             return hasTypedMessage ? helperMethod : null;
310         }
311
312         private static CodeMethodReturnStatement GenerateParameters(CodeMemberMethod helperMethod, CodeTypeDeclaration codeTypeDeclaration, CodeExpression target, FieldDirection dir)
313         {
314             CodeMethodReturnStatement returnStatement = null;
315             foreach (CodeTypeMember member in codeTypeDeclaration.Members)
316             {
317                 CodeMemberField field = member as CodeMemberField;
318                 if (field == null)
319                     continue;
320                 CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(target, field.Name);
321                 CodeTypeDeclaration bodyTypeDecl = ServiceContractGenerator.NamespaceHelper.GetCodeType(field.Type);
322                 if (bodyTypeDecl != null)
323                 {
324                     if (dir == FieldDirection.In)
325                         helperMethod.Statements.Add(new CodeAssignStatement(fieldRef, new CodeObjectCreateExpression(field.Type)));
326                     returnStatement = GenerateParameters(helperMethod, bodyTypeDecl, fieldRef, dir);
327                     continue;
328                 }
329                 CodeParameterDeclarationExpression param = GetRefParameter(helperMethod.Parameters, dir, field);
330                 if (param == null && dir == FieldDirection.Out && helperMethod.ReturnType.BaseType == voidTypeRef.BaseType)
331                 {
332                     helperMethod.ReturnType = field.Type;
333                     returnStatement = new CodeMethodReturnStatement(fieldRef);
334                 }
335                 else
336                 {
337                     if (param == null)
338                     {
339                         param = new CodeParameterDeclarationExpression(field.Type, NamingHelper.GetUniqueName(field.Name, DoesParameterNameExist, helperMethod));
340                         param.Direction = dir;
341                         helperMethod.Parameters.Add(param);
342                     }
343                     if (dir == FieldDirection.Out)
344                         helperMethod.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression(param.Name), fieldRef));
345                     else
346                         helperMethod.Statements.Add(new CodeAssignStatement(fieldRef, new CodeArgumentReferenceExpression(param.Name)));
347                 }
348             }
349             return returnStatement;
350         }
351
352         private static CodeParameterDeclarationExpression GetRefParameter(CodeParameterDeclarationExpressionCollection parameters, FieldDirection dir, CodeMemberField field)
353         {
354             foreach (CodeParameterDeclarationExpression p in parameters)
355             {
356                 if (p.Name == field.Name)
357                 {
358                     if (p.Direction != dir && p.Type.BaseType == field.Type.BaseType)
359                     {
360                         p.Direction = FieldDirection.Ref;
361                         return p;
362                     }
363                     return null;
364                 }
365             }
366             return null;
367         }
368
369         internal static bool DoesMemberNameExist(string name, object typeDeclarationObject)
370         {
371             CodeTypeDeclaration typeDeclaration = (CodeTypeDeclaration)typeDeclarationObject;
372
373             if (string.Compare(typeDeclaration.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
374             {
375                 return true;
376             }
377
378             foreach (CodeTypeMember member in typeDeclaration.Members)
379             {
380                 if (string.Compare(member.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
381                 {
382                     return true;
383                 }
384             }
385
386             return false;
387         }
388
389         internal static bool DoesTypeNameExists(string name, object codeTypeDeclarationCollectionObject)
390         {
391             CodeTypeDeclarationCollection codeTypeDeclarations = (CodeTypeDeclarationCollection)codeTypeDeclarationCollectionObject;
392             foreach (CodeTypeDeclaration codeTypeDeclaration in codeTypeDeclarations)
393             {
394                 if (string.Compare(codeTypeDeclaration.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
395                 {
396                     return true;
397                 }
398             }
399
400             return false;
401         }
402
403         internal static bool DoesTypeAndMemberNameExist(string name, object nameCollection)
404         {
405             object[] nameCollections = (object[])nameCollection;
406
407             if (DoesTypeNameExists(name, nameCollections[0]))
408             {
409                 return true;
410             }
411             if (DoesMemberNameExist(name, nameCollections[1]))
412             {
413                 return true;
414             }
415
416             return false;
417         }
418
419         internal static bool DoesMethodNameExist(string name, object operationsObject)
420         {
421             Collection<OperationContractGenerationContext> operations = (Collection<OperationContractGenerationContext>)operationsObject;
422             foreach (OperationContractGenerationContext operationContext in operations)
423             {
424                 if (String.Compare(operationContext.SyncMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
425                     return true;
426                 if (operationContext.IsAsync)
427                 {
428                     if (String.Compare(operationContext.BeginMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
429                         return true;
430                     if (String.Compare(operationContext.EndMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
431                         return true;
432                 }
433                 if (operationContext.IsTask)
434                 {
435                     if (String.Compare(operationContext.TaskMethod.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
436                         return true;
437                 }
438             }
439             return false;
440         }
441
442         internal static bool DoesParameterNameExist(string name, object methodObject)
443         {
444             CodeMemberMethod method = (CodeMemberMethod)methodObject;
445             if (String.Compare(method.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
446                 return true;
447             CodeParameterDeclarationExpressionCollection parameters = method.Parameters;
448             foreach (CodeParameterDeclarationExpression p in parameters)
449             {
450                 if (String.Compare(p.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
451                     return true;
452             }
453             return false;
454         }
455
456         static void AddMethodImpl(CodeMemberMethod method)
457         {
458             CodeMethodInvokeExpression methodInvoke = new CodeMethodInvokeExpression(GetChannelReference(), method.Name);
459             foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
460             {
461                 methodInvoke.Parameters.Add(new CodeDirectionExpression(parameter.Direction, new CodeVariableReferenceExpression(parameter.Name)));
462             }
463             if (IsVoid(method))
464                 method.Statements.Add(methodInvoke);
465             else
466                 method.Statements.Add(new CodeMethodReturnStatement(methodInvoke));
467         }
468
469         static CodeMemberMethod GetImplementationOfMethod(CodeTypeReference ifaceType, CodeMemberMethod method)
470         {
471             CodeMemberMethod m = new CodeMemberMethod();
472             m.Name = method.Name;
473             m.ImplementationTypes.Add(ifaceType);
474             m.Attributes = MemberAttributes.Public | MemberAttributes.Final;
475             foreach (CodeParameterDeclarationExpression parameter in method.Parameters)
476             {
477                 CodeParameterDeclarationExpression newParam = new CodeParameterDeclarationExpression(parameter.Type, parameter.Name);
478                 newParam.Direction = parameter.Direction;
479                 m.Parameters.Add(newParam);
480             }
481             m.ReturnType = method.ReturnType;
482             return m;
483         }
484
485         static void GenerateEventAsyncMethods(ServiceContractGenerationContext context, CodeTypeDeclaration clientType,
486             string syncMethodName, CodeMemberMethod beginMethod, CodeMemberMethod endMethod)
487         {
488             CodeTypeDeclaration operationCompletedEventArgsType = CreateOperationCompletedEventArgsType(context, syncMethodName, endMethod);
489             CodeMemberEvent operationCompletedEvent = CreateOperationCompletedEvent(context, clientType, syncMethodName, operationCompletedEventArgsType);
490
491             CodeMemberField beginOperationDelegate = CreateBeginOperationDelegate(context, clientType, syncMethodName);
492             CodeMemberMethod beginOperationMethod = CreateBeginOperationMethod(context, clientType, syncMethodName, beginMethod);
493
494             CodeMemberField endOperationDelegate = CreateEndOperationDelegate(context, clientType, syncMethodName);
495             CodeMemberMethod endOperationMethod = CreateEndOperationMethod(context, clientType, syncMethodName, endMethod);
496
497             CodeMemberField operationCompletedDelegate = CreateOperationCompletedDelegate(context, clientType, syncMethodName);
498             CodeMemberMethod operationCompletedMethod = CreateOperationCompletedMethod(context, clientType, syncMethodName, operationCompletedEventArgsType, operationCompletedEvent);
499
500             CodeMemberMethod eventAsyncMethod = CreateEventAsyncMethod(context, clientType, syncMethodName, beginMethod, 
501                 beginOperationDelegate, beginOperationMethod, endOperationDelegate, endOperationMethod, operationCompletedDelegate, operationCompletedMethod);
502
503             CreateEventAsyncMethodOverload(clientType, eventAsyncMethod);
504
505             // hide the normal async methods from intellisense
506             beginMethod.CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));
507             endMethod.CustomAttributes.Add(CreateEditorBrowsableAttribute(EditorBrowsableState.Advanced));            
508         }
509
510         static CodeTypeDeclaration CreateOperationCompletedEventArgsType(ServiceContractGenerationContext context, 
511             string syncMethodName, CodeMemberMethod endMethod)
512         {
513             if ((endMethod.Parameters.Count == 1) && (endMethod.ReturnType.BaseType == voidTypeRef.BaseType))
514             {
515                 // no need to create new event args type, use AsyncCompletedEventArgs
516                 return null;
517             }
518
519             CodeTypeDeclaration argsType = context.TypeFactory.CreateClassType();
520             argsType.BaseTypes.Add(new CodeTypeReference(asyncCompletedEventArgsType));
521
522             // define object[] results field.
523             CodeMemberField resultsField = new CodeMemberField();
524             resultsField.Type = new CodeTypeReference(objectArrayType);
525
526             CodeFieldReferenceExpression resultsFieldReference = new CodeFieldReferenceExpression();
527             resultsFieldReference.TargetObject = new CodeThisReferenceExpression();
528
529             // create constructor, that assigns the results field.
530             CodeConstructor ctor = new CodeConstructor();
531             ctor.Attributes = MemberAttributes.Public;
532             for (int i = 0; i < EventArgsCtorParamTypes.Length; i++)
533             {
534                 ctor.Parameters.Add(new CodeParameterDeclarationExpression(EventArgsCtorParamTypes[i], EventArgsCtorParamNames[i]));
535                 if (i > 0)
536                 {
537                     ctor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(EventArgsCtorParamNames[i]));
538                 }
539             }
540             argsType.Members.Add(ctor);
541             ctor.Statements.Add(new CodeAssignStatement(resultsFieldReference, new CodeVariableReferenceExpression(EventArgsCtorParamNames[0])));
542              
543             // create properties for the out parameters
544             int asyncResultParamIndex = GetAsyncResultParamIndex(endMethod);
545             int count = 0;
546             for (int i = 0; i < endMethod.Parameters.Count; i++)
547             {
548                 if (i != asyncResultParamIndex)
549                 {
550                     CreateEventAsyncCompletedArgsTypeProperty(argsType,
551                         endMethod.Parameters[i].Type,
552                         endMethod.Parameters[i].Name,
553                         new CodeArrayIndexerExpression(resultsFieldReference, new CodePrimitiveExpression(count++)));
554                 }
555             }
556
557             // create the property for the return type
558             if (endMethod.ReturnType.BaseType != voidTypeRef.BaseType)
559             {
560                 CreateEventAsyncCompletedArgsTypeProperty(
561                     argsType,
562                     endMethod.ReturnType,
563                     NamingHelper.GetUniqueName("Result", DoesMemberNameExist, argsType),
564                     new CodeArrayIndexerExpression(resultsFieldReference, 
565                         new CodePrimitiveExpression(count)));
566                
567             }
568
569             // Name the "results" field after generating the properties to make sure it does 
570             // not conflict with the property names.
571             resultsField.Name = NamingHelper.GetUniqueName("results", DoesMemberNameExist, argsType);
572             resultsFieldReference.FieldName = resultsField.Name;
573             argsType.Members.Add(resultsField);
574
575             // Name the type making sure that it does not conflict with its members and types already present in
576             // the namespace. 
577             argsType.Name = NamingHelper.GetUniqueName(GetOperationCompletedEventArgsTypeName(syncMethodName),
578                 DoesTypeAndMemberNameExist, new object[] { context.Namespace.Types, argsType });
579             context.Namespace.Types.Add(argsType);
580
581             return argsType;
582         }
583
584         static int GetAsyncResultParamIndex(CodeMemberMethod endMethod)
585         {
586             int index = endMethod.Parameters.Count - 1;
587             if (endMethod.Parameters[index].Type.BaseType != asyncResultTypeRef.BaseType)
588             {
589                 // workaround for CSD Dev Framework:10826, the unwrapped end method has IAsyncResult as first param. 
590                 index = 0;
591             }
592
593             return index;
594         }
595         
596         static CodeMemberProperty CreateEventAsyncCompletedArgsTypeProperty(CodeTypeDeclaration ownerTypeDecl, 
597             CodeTypeReference propertyType, string propertyName, CodeExpression propertyValueExpr)
598         {
599             CodeMemberProperty property = new CodeMemberProperty();
600             property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
601             property.Type = propertyType;
602             property.Name = propertyName;
603             property.HasSet = false;
604             property.HasGet = true;
605
606             CodeCastExpression castExpr = new CodeCastExpression(propertyType, propertyValueExpr);
607             CodeMethodReturnStatement returnStmt = new CodeMethodReturnStatement(castExpr);
608
609             property.GetStatements.Add(new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), raiseExceptionIfNecessaryMethodName));
610             property.GetStatements.Add(returnStmt);
611             ownerTypeDecl.Members.Add(property);
612
613             return property;
614         }
615
616         static CodeMemberEvent CreateOperationCompletedEvent(ServiceContractGenerationContext context, 
617             CodeTypeDeclaration clientType, string syncMethodName, CodeTypeDeclaration operationCompletedEventArgsType)
618         {
619             CodeMemberEvent operationCompletedEvent = new CodeMemberEvent();
620             operationCompletedEvent.Attributes = MemberAttributes.Public;
621             operationCompletedEvent.Type = new CodeTypeReference(eventHandlerType);
622             
623             if (operationCompletedEventArgsType == null)
624             {
625                 operationCompletedEvent.Type.TypeArguments.Add(asyncCompletedEventArgsType);
626             }
627             else
628             {
629                 operationCompletedEvent.Type.TypeArguments.Add(operationCompletedEventArgsType.Name);
630             }
631
632             operationCompletedEvent.Name = NamingHelper.GetUniqueName(GetOperationCompletedEventName(syncMethodName),
633                 DoesMethodNameExist, context.Operations);
634             
635             clientType.Members.Add(operationCompletedEvent);
636             return operationCompletedEvent;
637         }
638
639         static CodeMemberField CreateBeginOperationDelegate(ServiceContractGenerationContext context,
640             CodeTypeDeclaration clientType, string syncMethodName)
641         {
642             CodeMemberField beginOperationDelegate = new CodeMemberField();
643             beginOperationDelegate.Attributes = MemberAttributes.Private;
644             beginOperationDelegate.Type = new CodeTypeReference(beginOperationDelegateTypeName);
645             beginOperationDelegate.Name = NamingHelper.GetUniqueName(GetBeginOperationDelegateName(syncMethodName),
646                 DoesMethodNameExist, context.Operations);
647
648             clientType.Members.Add(beginOperationDelegate);
649             return beginOperationDelegate;
650         }
651
652         static CodeMemberMethod CreateBeginOperationMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType, 
653             string syncMethodName, CodeMemberMethod beginMethod)
654         {
655             CodeMemberMethod onBeginOperationMethod = new CodeMemberMethod();
656             onBeginOperationMethod.Attributes = MemberAttributes.Private;
657             onBeginOperationMethod.ReturnType = new CodeTypeReference(asyncResultType);
658             onBeginOperationMethod.Name = NamingHelper.GetUniqueName(GetBeginOperationMethodName(syncMethodName), 
659                 DoesMethodNameExist, context.Operations);
660
661             CodeParameterDeclarationExpression inValuesParam = new CodeParameterDeclarationExpression();
662             inValuesParam.Type = new CodeTypeReference(objectArrayType);
663             inValuesParam.Name = NamingHelper.GetUniqueName("inValues", DoesParameterNameExist, beginMethod);
664             onBeginOperationMethod.Parameters.Add(inValuesParam);
665
666             CodeMethodInvokeExpression invokeBegin = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), beginMethod.Name);
667             CodeExpression inValuesRef = new CodeVariableReferenceExpression(inValuesParam.Name);
668
669             for (int i = 0; i < beginMethod.Parameters.Count - 2; i++)
670             {
671                 CodeVariableDeclarationStatement variableDecl = new CodeVariableDeclarationStatement();
672                 variableDecl.Type = beginMethod.Parameters[i].Type;
673                 variableDecl.Name = beginMethod.Parameters[i].Name;
674                 variableDecl.InitExpression = new CodeCastExpression(variableDecl.Type,
675                     new CodeArrayIndexerExpression(inValuesRef, new CodePrimitiveExpression(i)));
676
677                 onBeginOperationMethod.Statements.Add(variableDecl);
678                 invokeBegin.Parameters.Add(new CodeDirectionExpression(beginMethod.Parameters[i].Direction,
679                     new CodeVariableReferenceExpression(variableDecl.Name)));
680             }
681
682             for (int i = beginMethod.Parameters.Count - 2; i < beginMethod.Parameters.Count; i++)
683             {
684                 onBeginOperationMethod.Parameters.Add(new CodeParameterDeclarationExpression(
685                     beginMethod.Parameters[i].Type, beginMethod.Parameters[i].Name));
686                 invokeBegin.Parameters.Add(new CodeVariableReferenceExpression(beginMethod.Parameters[i].Name));
687             }
688
689             onBeginOperationMethod.Statements.Add(new CodeMethodReturnStatement(invokeBegin));
690             clientType.Members.Add(onBeginOperationMethod);
691             return onBeginOperationMethod;
692         }
693        
694         static CodeMemberField CreateEndOperationDelegate(ServiceContractGenerationContext context,
695             CodeTypeDeclaration clientType, string syncMethodName)
696         {
697             CodeMemberField endOperationDelegate = new CodeMemberField();
698             endOperationDelegate.Attributes = MemberAttributes.Private;
699             endOperationDelegate.Type = new CodeTypeReference(endOperationDelegateTypeName);
700             endOperationDelegate.Name = NamingHelper.GetUniqueName(GetEndOperationDelegateName(syncMethodName),
701                 DoesMethodNameExist, context.Operations);
702
703             clientType.Members.Add(endOperationDelegate);
704             return endOperationDelegate;
705         }
706
707         static CodeMemberMethod CreateEndOperationMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType, string syncMethodName, CodeMemberMethod endMethod)
708         {
709             CodeMemberMethod onEndOperationMethod = new CodeMemberMethod();
710             onEndOperationMethod.Attributes = MemberAttributes.Private;
711             onEndOperationMethod.ReturnType = new CodeTypeReference(objectArrayType);
712             onEndOperationMethod.Name = NamingHelper.GetUniqueName(GetEndOperationMethodName(syncMethodName), DoesMethodNameExist, context.Operations);
713
714             int asyncResultParamIndex = GetAsyncResultParamIndex(endMethod);
715             CodeMethodInvokeExpression invokeEnd = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), endMethod.Name);
716             CodeArrayCreateExpression retArray = new CodeArrayCreateExpression();
717             retArray.CreateType = new CodeTypeReference(objectArrayType);
718             for (int i = 0; i < endMethod.Parameters.Count; i++)
719             {
720                 if (i == asyncResultParamIndex)
721                 {
722                     onEndOperationMethod.Parameters.Add(new CodeParameterDeclarationExpression(
723                         endMethod.Parameters[i].Type, endMethod.Parameters[i].Name));
724                     invokeEnd.Parameters.Add(new CodeVariableReferenceExpression(endMethod.Parameters[i].Name));
725                 }
726                 else
727                 {
728                     CodeVariableDeclarationStatement variableDecl = new CodeVariableDeclarationStatement(
729                         endMethod.Parameters[i].Type, endMethod.Parameters[i].Name);
730                     CodeMethodReferenceExpression getDefaultValueMethodRef = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), getDefaultValueForInitializationMethodName, endMethod.Parameters[i].Type);
731                     variableDecl.InitExpression = new CodeMethodInvokeExpression(getDefaultValueMethodRef); 
732                     onEndOperationMethod.Statements.Add(variableDecl);
733
734                     invokeEnd.Parameters.Add(new CodeDirectionExpression(endMethod.Parameters[i].Direction,
735                             new CodeVariableReferenceExpression(variableDecl.Name)));
736
737                     retArray.Initializers.Add(new CodeVariableReferenceExpression(variableDecl.Name));
738                 }
739             }
740
741             if (endMethod.ReturnType.BaseType != voidTypeRef.BaseType)
742             {
743                 CodeVariableDeclarationStatement retValDecl = new CodeVariableDeclarationStatement();
744                 retValDecl.Type = endMethod.ReturnType;
745                 retValDecl.Name = NamingHelper.GetUniqueName("retVal", DoesParameterNameExist, endMethod);
746                 retValDecl.InitExpression = invokeEnd;
747                 retArray.Initializers.Add(new CodeVariableReferenceExpression(retValDecl.Name));
748
749                 onEndOperationMethod.Statements.Add(retValDecl);
750             }
751             else
752             {
753                 onEndOperationMethod.Statements.Add(invokeEnd);
754             }
755
756             if (retArray.Initializers.Count > 0)
757             {
758                 onEndOperationMethod.Statements.Add(new CodeMethodReturnStatement(retArray));
759             }
760             else
761             {
762                 onEndOperationMethod.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(null)));
763             }
764
765             clientType.Members.Add(onEndOperationMethod);
766             return onEndOperationMethod;
767         }
768
769         static CodeMemberField CreateOperationCompletedDelegate(ServiceContractGenerationContext context, 
770             CodeTypeDeclaration clientType, string syncMethodName)
771         {
772             CodeMemberField operationCompletedDelegate = new CodeMemberField();
773             operationCompletedDelegate.Attributes = MemberAttributes.Private;
774             operationCompletedDelegate.Type = new CodeTypeReference(sendOrPostCallbackType);
775             operationCompletedDelegate.Name = NamingHelper.GetUniqueName(GetOperationCompletedDelegateName(syncMethodName),
776                 DoesMethodNameExist, context.Operations);
777
778             clientType.Members.Add(operationCompletedDelegate);
779             return operationCompletedDelegate;
780         }
781
782         static CodeMemberMethod CreateOperationCompletedMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType, 
783             string syncMethodName, CodeTypeDeclaration operationCompletedEventArgsType, CodeMemberEvent operationCompletedEvent)
784         {
785             CodeMemberMethod operationCompletedMethod = new CodeMemberMethod();
786             operationCompletedMethod.Attributes = MemberAttributes.Private;
787             operationCompletedMethod.Name = NamingHelper.GetUniqueName(GetOperationCompletedMethodName(syncMethodName), 
788                 DoesMethodNameExist, context.Operations);
789
790             operationCompletedMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(objectType), "state"));
791             operationCompletedMethod.ReturnType = new CodeTypeReference(voidType);
792
793             CodeVariableDeclarationStatement eventArgsDecl =
794                 new CodeVariableDeclarationStatement(invokeAsyncCompletedEventArgsTypeName, "e");
795
796             eventArgsDecl.InitExpression = new CodeCastExpression(invokeAsyncCompletedEventArgsTypeName,
797                 new CodeArgumentReferenceExpression(operationCompletedMethod.Parameters[0].Name));
798
799             CodeObjectCreateExpression newEventArgsExpr;
800             CodeVariableReferenceExpression eventArgsRef = new CodeVariableReferenceExpression(eventArgsDecl.Name);
801             if (operationCompletedEventArgsType != null)
802             {
803                 newEventArgsExpr = new CodeObjectCreateExpression(operationCompletedEventArgsType.Name,
804                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[0]),
805                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[1]),
806                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[2]),
807                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[3]));
808             }
809             else
810             {
811                 newEventArgsExpr = new CodeObjectCreateExpression(asyncCompletedEventArgsType,
812                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[1]),
813                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[2]),
814                     new CodePropertyReferenceExpression(eventArgsRef, EventArgsPropertyNames[3]));
815             }
816
817             CodeEventReferenceExpression completedEvent = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), operationCompletedEvent.Name);
818
819             CodeDelegateInvokeExpression raiseEventExpr = new CodeDelegateInvokeExpression(
820                 completedEvent,
821                 new CodeThisReferenceExpression(),
822                 newEventArgsExpr);
823
824             CodeConditionStatement ifEventHandlerNotNullBlock = new CodeConditionStatement(
825                 new CodeBinaryOperatorExpression(
826                     completedEvent,
827                     CodeBinaryOperatorType.IdentityInequality,
828                     new CodePrimitiveExpression(null)),
829                 eventArgsDecl,
830                 new CodeExpressionStatement(raiseEventExpr));
831
832             operationCompletedMethod.Statements.Add(ifEventHandlerNotNullBlock);
833
834             clientType.Members.Add(operationCompletedMethod);
835             return operationCompletedMethod;
836         }
837         
838         static CodeMemberMethod CreateEventAsyncMethod(ServiceContractGenerationContext context, CodeTypeDeclaration clientType, 
839             string syncMethodName, CodeMemberMethod beginMethod,
840             CodeMemberField beginOperationDelegate, CodeMemberMethod beginOperationMethod, 
841             CodeMemberField endOperationDelegate, CodeMemberMethod endOperationMethod, 
842             CodeMemberField operationCompletedDelegate, CodeMemberMethod operationCompletedMethod)
843         {
844             CodeMemberMethod eventAsyncMethod = new CodeMemberMethod();
845             eventAsyncMethod.Name = NamingHelper.GetUniqueName(GetEventAsyncMethodName(syncMethodName), 
846                 DoesMethodNameExist, context.Operations);
847             eventAsyncMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
848             eventAsyncMethod.ReturnType = new CodeTypeReference(voidType);
849
850             CodeArrayCreateExpression invokeAsyncInValues = new CodeArrayCreateExpression(new CodeTypeReference(objectArrayType));
851             for (int i = 0; i < beginMethod.Parameters.Count - 2; i++)
852             {
853                 CodeParameterDeclarationExpression beginMethodParameter = beginMethod.Parameters[i];
854                 CodeParameterDeclarationExpression eventAsyncMethodParameter = new CodeParameterDeclarationExpression(
855                     beginMethodParameter.Type, beginMethodParameter.Name);
856
857                 eventAsyncMethodParameter.Direction = FieldDirection.In;
858                 eventAsyncMethod.Parameters.Add(eventAsyncMethodParameter);
859                 invokeAsyncInValues.Initializers.Add(new CodeVariableReferenceExpression(eventAsyncMethodParameter.Name));
860             }
861
862             string userStateParamName = NamingHelper.GetUniqueName("userState", DoesParameterNameExist, eventAsyncMethod);
863             eventAsyncMethod.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(objectType), userStateParamName));
864             
865             eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(beginOperationDelegate, beginOperationMethod));
866             eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(endOperationDelegate, endOperationMethod));
867             eventAsyncMethod.Statements.Add(CreateDelegateIfNotNull(operationCompletedDelegate, operationCompletedMethod));
868
869             CodeMethodInvokeExpression invokeAsync = new CodeMethodInvokeExpression(new CodeBaseReferenceExpression(), invokeAsyncMethodName);
870             invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), beginOperationDelegate.Name));
871             if (invokeAsyncInValues.Initializers.Count > 0)
872             {
873                 invokeAsync.Parameters.Add(invokeAsyncInValues);
874             }
875             else
876             {
877                 invokeAsync.Parameters.Add(new CodePrimitiveExpression(null));
878             }
879             invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), endOperationDelegate.Name));
880             invokeAsync.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), operationCompletedDelegate.Name));
881             invokeAsync.Parameters.Add(new CodeVariableReferenceExpression(userStateParamName));
882         
883             eventAsyncMethod.Statements.Add(new CodeExpressionStatement(invokeAsync));
884
885             clientType.Members.Add(eventAsyncMethod);
886             return eventAsyncMethod;
887         }
888
889         static CodeMemberMethod CreateEventAsyncMethodOverload(CodeTypeDeclaration clientType, CodeMemberMethod eventAsyncMethod)
890         {
891             CodeMemberMethod eventAsyncMethodOverload = new CodeMemberMethod();
892             eventAsyncMethodOverload.Attributes = eventAsyncMethod.Attributes;
893             eventAsyncMethodOverload.Name = eventAsyncMethod.Name;
894             eventAsyncMethodOverload.ReturnType = eventAsyncMethod.ReturnType;
895
896             CodeMethodInvokeExpression invokeEventAsyncMethod = new CodeMethodInvokeExpression(
897                 new CodeThisReferenceExpression(), eventAsyncMethod.Name);
898
899             for (int i = 0; i < eventAsyncMethod.Parameters.Count - 1; i++)
900             {
901                 eventAsyncMethodOverload.Parameters.Add(new CodeParameterDeclarationExpression(
902                     eventAsyncMethod.Parameters[i].Type,
903                     eventAsyncMethod.Parameters[i].Name));
904
905                 invokeEventAsyncMethod.Parameters.Add(new CodeVariableReferenceExpression(
906                     eventAsyncMethod.Parameters[i].Name));
907             }
908             invokeEventAsyncMethod.Parameters.Add(new CodePrimitiveExpression(null));
909
910             eventAsyncMethodOverload.Statements.Add(invokeEventAsyncMethod);
911
912             int eventAsyncMethodPosition = clientType.Members.IndexOf(eventAsyncMethod);
913             Fx.Assert(eventAsyncMethodPosition != -1,
914                 "The eventAsyncMethod must be added to the clientType before calling CreateEventAsyncMethodOverload");
915
916             clientType.Members.Insert(eventAsyncMethodPosition, eventAsyncMethodOverload);
917             return eventAsyncMethodOverload;
918         }
919
920         static CodeStatement CreateDelegateIfNotNull(CodeMemberField delegateField, CodeMemberMethod delegateMethod)
921         {
922             return new CodeConditionStatement(
923                 new CodeBinaryOperatorExpression(
924                     new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), delegateField.Name),
925                     CodeBinaryOperatorType.IdentityEquality,
926                     new CodePrimitiveExpression(null)),
927                 new CodeAssignStatement(
928                     new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), delegateField.Name),
929                     new CodeDelegateCreateExpression(delegateField.Type, 
930                         new CodeThisReferenceExpression(), delegateMethod.Name)));
931         }
932
933         static string GetClassName(string interfaceName)
934         {
935             // maybe strip a leading 'I'
936             if (interfaceName.Length >= 2 &&
937                 String.Compare(interfaceName, 0, Strings.InterfaceTypePrefix, 0, Strings.InterfaceTypePrefix.Length, StringComparison.Ordinal) == 0 &&
938                 Char.IsUpper(interfaceName, 1))
939                 return interfaceName.Substring(1);
940             else
941                 return interfaceName;
942         }
943
944         static string GetEventAsyncMethodName(string syncMethodName)
945         {
946             return string.Format(CultureInfo.InvariantCulture, "{0}Async", syncMethodName);
947         }
948
949         static string GetBeginOperationDelegateName(string syncMethodName)
950         {
951             return string.Format(CultureInfo.InvariantCulture, "onBegin{0}Delegate", syncMethodName);
952         }
953
954         static string GetBeginOperationMethodName(string syncMethodName)
955         {
956             return string.Format(CultureInfo.InvariantCulture, "OnBegin{0}", syncMethodName);
957         }
958
959         static string GetEndOperationDelegateName(string syncMethodName)
960         {
961             return string.Format(CultureInfo.InvariantCulture, "onEnd{0}Delegate", syncMethodName);
962         }
963
964         static string GetEndOperationMethodName(string syncMethodName)
965         {
966             return string.Format(CultureInfo.InvariantCulture, "OnEnd{0}", syncMethodName);
967         }
968
969         static string GetOperationCompletedDelegateName(string syncMethodName)
970         {
971             return string.Format(CultureInfo.InvariantCulture, "on{0}CompletedDelegate", syncMethodName);
972         }
973
974         static string GetOperationCompletedMethodName(string syncMethodName)
975         {
976             return string.Format(CultureInfo.InvariantCulture, "On{0}Completed", syncMethodName);
977         }
978
979         static string GetOperationCompletedEventName(string syncMethodName)
980         {
981             return string.Format(CultureInfo.InvariantCulture, "{0}Completed", syncMethodName);
982         }
983
984         static string GetOperationCompletedEventArgsTypeName(string syncMethodName)
985         {
986             return string.Format(CultureInfo.InvariantCulture, "{0}CompletedEventArgs", syncMethodName);
987         }
988
989         static internal string GetClientClassName(string interfaceName)
990         {
991             return GetClassName(interfaceName) + Strings.ClientTypeSuffix;
992         }
993
994         static bool IsVoid(CodeMemberMethod method)
995         {
996             return method.ReturnType == null || String.Compare(method.ReturnType.BaseType, typeof(void).FullName, StringComparison.Ordinal) == 0;
997         }
998
999         static CodeExpression GetChannelReference()
1000         {
1001             return new CodePropertyReferenceExpression(new CodeBaseReferenceExpression(), Strings.ClientBaseChannelProperty);
1002         }
1003
1004         static class Strings
1005         {
1006             public const string ClientBaseChannelProperty = "Channel";
1007             public const string ClientTypeSuffix = "Client";
1008             public const string InterfaceTypePrefix = "I";
1009         }
1010     }
1011 }