using System;
using System.Collections.Generic;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
namespace AsyncGen
{
static class Program
{
static void Main(string[] args)
{
List<string> assemblies = ParseCommandLine(args);
#region Load the specified assembly.
if (!File.Exists(assemblies[0]))
{
Console.Error.WriteLine("File not found: {0}", assemblies[0]);
return;
}
Assembly asm = Assembly.LoadFrom(assemblies[0]);
#endregion
foreach (Type serverType in asm.GetExportedTypes())
{
// Only treat types marked with the [GenerateAsyncClient] attribute.
object[] asyncClientClassAttributes = serverType.GetCustomAttributes(typeof(GenerateAsyncClientClassAttribute), false);
if (asyncClientClassAttributes.Length == 0)
{
continue;
}
#if USE_SNIPPETS
addAccessorBodies.Clear();
removeAccessorBodies.Clear();
#endif
GenerateAsyncClientClassAttribute asyncClientClassAttribute = (GenerateAsyncClientClassAttribute)asyncClientClassAttributes[0];
string asyncClientClassName =
string.IsNullOrEmpty(asyncClientClassAttribute.ClassName)
? (serverType.IsInterface && serverType.Name.StartsWith("I") ? serverType.Name.Substring(1) : serverType.Name) + "Client"
: asyncClientClassAttribute.ClassName;
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace nameSpace = MakeNamespace(serverType, compileUnit);
CodeTypeDeclaration asyncClientClass = MakeAsyncClientClass(serverType, asyncClientClassName, nameSpace);
CodeConstructor ctor = MakeConstructorSkeleton();
ctor.Parameters.Add(new CodeParameterDeclarationExpression(serverType, "server"));
ctor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("server"));
nameSpace.Types.Add(asyncClientClass);
asyncClientClass.Members.Add(ctor);
foreach (MethodInfo method in serverType.GetMethods())
{
if (!method.IsPublic)
{
continue;
}
object[] asyncOperationAttributes = method.GetCustomAttributes(typeof(GenerateAsyncOperationAttribute), false);
if (asyncOperationAttributes.Length == 0)
{
continue;
}
GenerateAsyncOperationAttribute asyncOperationAttribute = (GenerateAsyncOperationAttribute)asyncOperationAttributes[0];
GenerateAsyncOperation(serverType.Name, asyncClientClass, method, ctor, asyncOperationAttribute);
}
switch (outputLanguage)
{
case OutputLanguage.CS:
codeDomProvider = new Microsoft.CSharp.CSharpCodeProvider();
break;
case OutputLanguage.VB:
codeDomProvider = new Microsoft.VisualBasic.VBCodeProvider();
break;
#if !USE_SNIPPETS
case OutputLanguage.CPP:
codeDomProvider = new Microsoft.VisualC.CppCodeProvider();
break;
#endif
default:
Debug.Fail(string.Format("Invalid language ({0})", outputLanguage));
break;
}
string sourceFileName = asyncClientClassName + ".generated." + codeDomProvider.FileExtension;
GenerateCode(compileUnit, codeDomProvider, sourceFileName);
CompileGeneratedCode(assemblies, codeDomProvider, sourceFileName);
}
Pause();
}
private static List<string> ParseCommandLine(string[] args)
{
if (args.Length < 1)
{
Usage();
}
List<string> assemblyNames = new List<string>(args.Length);
for (int i = 0; i < args.Length; i++)
{
if (!args[i].StartsWith("-") && !args[i].StartsWith("/"))
{
assemblyNames.Add(args[i]);
}
else
{
string[] words = args[i].Split(':');
if (5 <= words[0].Length && words[0].Substring(1, 4).ToLower() == "lang")
{
if (words.Length < 2)
{
Console.Error.WriteLine("Language identifier expected after \"/language\".");
Usage();
}
else
{
try
{
outputLanguage = (OutputLanguage)Enum.Parse(typeof(OutputLanguage), words[1], true);
}
catch (ArgumentException)
{
Console.Error.WriteLine("Unrecognized language identifier: {0}.", words[1]);
Console.Error.Write("Must be one of the following:");
foreach (OutputLanguage language in Enum.GetValues(typeof(OutputLanguage)))
{
Console.Error.Write(" {0}", language);
}
Console.Error.WriteLine();
Usage();
}
}
}
else
{
Console.Error.WriteLine("Unrecognized option: \"{0}\".", args[i]);
Usage();
}
}
}
if (0 == assemblyNames.Count)
{
Usage();
}
return assemblyNames;
}
private static void Usage()
{
Console.Error.WriteLine("USAGE: AsyncGen [ /language:<language identifier> ] <assembly> [ <additional assembly needed for compiling the generated code>+ ]");
Pause();
Environment.Exit(-1);
}
private static void Pause()
{
if (Debugger.IsAttached)
{
Console.Error.WriteLine("Press Enter to continue...");
Console.In.ReadLine();
}
}
private static CodeNamespace MakeNamespace(Type serverType, CodeCompileUnit compileUnit)
{
CodeNamespace value = new CodeNamespace(serverType.Namespace);
value.Imports.Add(new CodeNamespaceImport("System"));
value.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
value.Imports.Add(new CodeNamespaceImport("System.Diagnostics"));
value.Imports.Add(new CodeNamespaceImport("AsyncGen"));
compileUnit.Namespaces.Add(value);
return value;
}
private static CodeTypeDeclaration MakeAsyncClientClass(Type serverType, string asyncClientClassName, CodeNamespace nameSpace)
{
CodeTypeDeclaration value = new CodeTypeDeclaration(asyncClientClassName);
value.IsPartial = true;
value.BaseTypes.Add(new CodeTypeReference("ClientBase", new CodeTypeReference(serverType)));
return value;
}
private static void GenerateAsyncOperation(string serverTypeName, CodeTypeDeclaration asyncClientClass, MethodInfo method, CodeConstructor clientCtor, GenerateAsyncOperationAttribute asyncOperationAttribute)
{
string operationBaseName = string.IsNullOrEmpty(asyncOperationAttribute.BaseName) ? method.Name : asyncOperationAttribute.BaseName;
string asyncMethodName = string.IsNullOrEmpty(asyncOperationAttribute.StartMethodName) ? operationBaseName + "Async" : asyncOperationAttribute.StartMethodName;
string cancelMethodName = string.IsNullOrEmpty(asyncOperationAttribute.CancelMethodName) ? operationBaseName + "AsyncCancel" : asyncOperationAttribute.CancelMethodName;
string completionEventName = string.IsNullOrEmpty(asyncOperationAttribute.CompletedEventName) ? operationBaseName + "Completed" : asyncOperationAttribute.CompletedEventName;
string outputTypeName = string.IsNullOrEmpty(asyncOperationAttribute.OutputTypeName) ? operationBaseName + "Output" : asyncOperationAttribute.OutputTypeName;
string delegateTypeName = operationBaseName + "Delegate";
string trackerClassName = operationBaseName + "Tracker";
string trackerFieldName = "_" + operationBaseName.ToLower() + "Tracker";
#region Identify special parameters.
ParameterInfo taskIDParam = null, callbackParam = null;
foreach (ParameterInfo param in method.GetParameters())
{
object[] userStateAttributes = param.GetCustomAttributes(typeof(TaskIDAttribute), false);
if (userStateAttributes.Length > 0)
{
taskIDParam = param;
}
}
#endregion
asyncClientClass.Members.Add(MakeSyncMethod(asyncClientClass, method, asyncOperationAttribute.CallbackInterface, trackerFieldName, taskIDParam));
CodeTypeDeclaration outputType = MakeOutputType(method, outputTypeName);
if (outputType.Members.Count > 1)
{
AddNewMember(asyncClientClass, outputType);
}
clientCtor.Statements.Add(MakeTrackerInitializationStatement(trackerClassName, trackerFieldName));
#if !USE_SNIPPETS
clientCtor.Statements.Add(MakeAttachTrackerCompletedEventStatement(trackerFieldName, "OperationCompleted", outputType));
#endif
asyncClientClass.Members.Add(MakeAsyncMethod(method, taskIDParam, new ParameterInfo[] { taskIDParam, callbackParam }, asyncOperationAttribute.CallbackInterface, delegateTypeName, asyncMethodName, trackerFieldName));
if (asyncOperationAttribute.GenerateCancelMethod)
{
CodeMemberMethod cancelMethod = GetMethod(asyncClientClass, cancelMethodName);
if (cancelMethod == null)
{
asyncClientClass.Members.Add(MakeCancelMethod(method, cancelMethodName, trackerFieldName));
}
else
{
CodeStatement lastStatement = cancelMethod.Statements[cancelMethod.Statements.Count - 1];
cancelMethod.Statements.RemoveAt(cancelMethod.Statements.Count - 1);
cancelMethod.Statements.Add(MakeTrackerCancelOperationMethodInvocation(trackerFieldName, taskIDParam));
cancelMethod.Statements.Add(lastStatement);
}
}
AddNewMember(asyncClientClass, MakeCompletionEvent(completionEventName, trackerFieldName, outputType));
asyncClientClass.Members.Add(MakeTrackerClass(method, asyncClientClass, clientCtor, serverTypeName, trackerClassName, trackerFieldName, delegateTypeName, outputType, asyncOperationAttribute));
asyncClientClass.Members.Add(MakeTrackerField(trackerClassName, trackerFieldName));
#if !USE_SNIPPETS
asyncClientClass.Members.Add(MakeTrackerCompletionEventHandler(completionEventName, trackerFieldName, outputType));
#endif
asyncClientClass.Members.Add(MakeDelegateType(method, delegateTypeName));
}
private static CodeMemberMethod GetMethod(CodeTypeDeclaration asyncClientClass, string methodName)
{
foreach (CodeTypeMember member in asyncClientClass.Members)
{
CodeMemberMethod method = member as CodeMemberMethod;
if (method != null && method.Name == methodName)
{
return method;
}
}
return null;
}
private static CodeMemberMethod MakeSyncMethod(CodeTypeDeclaration asyncClientClass, MethodInfo method, Type callbackInterface, string trackerFieldName, ParameterInfo taskIDParam)
{
CodeMemberMethod value = MakeSyncMethodSkeleton(method, callbackInterface);
CodeMethodInvokeExpression serverMethodInvocation = new CodeMethodInvokeExpression();
serverMethodInvocation.Method.TargetObject = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "server");
serverMethodInvocation.Method.MethodName = method.Name;
foreach (ParameterInfo param in method.GetParameters())
{
serverMethodInvocation.Parameters.Add(
param.ParameterType == callbackInterface
? (CodeExpression)new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName)
: (CodeExpression)MakeInvocationArgument(param));
}
if (method.ReturnType != typeof(void))
{
value.Statements.Add(new CodeVariableDeclarationStatement(method.ReturnType, "value"));
}
CodeMethodInvokeExpression createOperationInvocation = new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName), "CreateOperation");
if (taskIDParam != null)
{
createOperationInvocation.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
value.Statements.Add(createOperationInvocation);
CodeTryCatchFinallyStatement tryFinallyStatement = new CodeTryCatchFinallyStatement();
tryFinallyStatement.TryStatements.Add(
method.ReturnType == typeof(void)
? (CodeStatement)new CodeExpressionStatement(serverMethodInvocation)
: (CodeStatement)new CodeAssignStatement(new CodeVariableReferenceExpression("value"), serverMethodInvocation));
CodeMethodInvokeExpression completeOperationInvocation = new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName), "CompleteOperation");
if (taskIDParam != null)
{
completeOperationInvocation.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
tryFinallyStatement.FinallyStatements.Add(completeOperationInvocation);
value.Statements.Add(tryFinallyStatement);
if (method.ReturnType != typeof(void))
{
value.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("value")));
}
return value;
}
private static CodeMemberMethod MakeSyncMethodSkeleton(MethodInfo method, Type callbackInterface)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
value.ReturnType = new CodeTypeReference(method.ReturnType);
value.Name = method.Name;
foreach (ParameterInfo param in method.GetParameters())
{
if (param.ParameterType != callbackInterface)
{
value.Parameters.Add(MakeParameterDeclaration(param));
}
}
return value;
}
private static CodeAssignStatement MakeTrackerInitializationStatement(string trackerClassName, string trackerFieldName)
{
return new CodeAssignStatement(
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName),
new CodeObjectCreateExpression(trackerClassName,
new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "server"),
new CodeThisReferenceExpression()));
}
private static void ImplementCallbackInterface(Type callbackInterface, CodeConstructor clientCtor, CodeTypeDeclaration asyncClientClass, CodeTypeDeclaration trackerClass, string trackerFieldName, string operationBaseName)
{
foreach (MethodInfo interfaceMethod in callbackInterface.GetMethods())
{
CodeMemberMethod implementingMethod = MakeCallbackMethodSkeleton(callbackInterface, interfaceMethod);
object[] progressEventAttributes = interfaceMethod.GetCustomAttributes(typeof(GenerateProgressEventAttribute), false);
if (progressEventAttributes.Length == 0)
{
implementingMethod.Statements.Add(new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(Exception), new CodePrimitiveExpression("The operation is not implemented."))));
}
else
{
GenerateProgressEventAttribute progressEventAttribute = (GenerateProgressEventAttribute)progressEventAttributes[0];
string progressEventName = progressEventAttribute.EventName == null ? operationBaseName + "ProgressChanged" : progressEventAttribute.EventName;
string onProgressChangedMethodName = "On" + progressEventName;
string intermediateResultsTypeName = progressEventAttribute.ResultsTypeName == null ? operationBaseName + "IntermediateResults" : progressEventAttribute.ResultsTypeName;
CodeTypeDeclaration intermediateResultsType = MakeIntermediateResultsType(interfaceMethod, intermediateResultsTypeName);
if (intermediateResultsType.Members.Count > 1)
{
AddNewMember(asyncClientClass, intermediateResultsType);
}
AddNewMember(trackerClass, MakeOnProgressChangedMethod(progressEventName, intermediateResultsType));
AddNewMember(trackerClass, MakeSimpleProgressEvent(progressEventName, intermediateResultsType));
#if USE_SNIPPETS
AddNewMember(asyncClientClass,
MakeCustomProgressEvent(progressEventName, trackerFieldName, intermediateResultsType));
#else
AddNewMember(asyncClientClass,
MakeSimpleProgressEvent(progressEventName, intermediateResultsType));
AddNewMember(asyncClientClass, MakeTrackerProgressEventHandler(progressEventName, trackerFieldName, intermediateResultsType));
clientCtor.Statements.Add(MakeAttachTrackerProgressEventStatement(trackerFieldName, progressEventName, intermediateResultsType));
#endif
ImplementCallbackMethod(asyncClientClass, implementingMethod, interfaceMethod, progressEventAttribute, operationBaseName, onProgressChangedMethodName, intermediateResultsType);
}
trackerClass.Members.Add(implementingMethod);
}
}
private static void ImplementCallbackMethod(CodeTypeDeclaration asyncClientClass, CodeMemberMethod implementationMethod, MethodInfo interfaceMethod, GenerateProgressEventAttribute progressEventAttribute, string operationBaseName, string onProgressChangedMethodName, CodeTypeDeclaration intermediateResultsType)
{
#region Identify special parameters.
ParameterInfo progressPercentageParam = null, taskIDParam = null, cancelFlag = null;
foreach (ParameterInfo interfaceParam in interfaceMethod.GetParameters())
{
IdentifySpecialCallbackParameters(ref progressPercentageParam, ref taskIDParam, ref cancelFlag, interfaceParam);
}
IdentifySpecialCallbackParameters(ref progressPercentageParam, ref taskIDParam, ref cancelFlag, interfaceMethod.ReturnParameter);
#endregion
#region Validate attribute consistency.
if (cancelFlag != null && (!cancelFlag.IsOut && !cancelFlag.IsRetval && !string.IsNullOrEmpty(cancelFlag.Name) || cancelFlag.ParameterType.FullName.StartsWith("Boolean")))
{
throw new ApplicationException("The [CancelFlag] attribute can only be applied to \"out bool\" parameters.");
}
//if (cancelFlag != null && progressEventAttribute.Async)
//{
// throw new ApplicationException("[CancelFlag] specified but the callback is asynchronous. Use [GenerateProgressEvent(Async = false)] to make it synchronous.");
//}
#endregion
if (intermediateResultsType.Members.Count > 1)
{
implementationMethod.Statements.Add(new CodeVariableDeclarationStatement(intermediateResultsType.Name, "results", new CodeObjectCreateExpression(intermediateResultsType.Name)));
foreach (ParameterInfo param in interfaceMethod.GetParameters())
{
if (!param.IsOut && param != progressPercentageParam && param != taskIDParam)
{
CodeFieldReferenceExpression fieldRef = new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("results"), param.Name);
CodeArgumentReferenceExpression argRef = new CodeArgumentReferenceExpression(param.Name);
implementationMethod.Statements.Add(new CodeAssignStatement(fieldRef, argRef));
}
}
}
CodeMethodReferenceExpression sendOrPostProgressMethod = new CodeMethodReferenceExpression(
new CodeThisReferenceExpression(),
progressEventAttribute.Async ? "PostProgress" : "SendProgress");
if (intermediateResultsType.Members.Count > 0)
{
sendOrPostProgressMethod.TypeArguments.Add(intermediateResultsType.Name);
}
CodeMethodInvokeExpression sendOrPostProgressInvocation =
new CodeMethodInvokeExpression(sendOrPostProgressMethod,
new CodeDelegateCreateExpression(
new CodeTypeReference(typeof(SendOrPostCallback)),
new CodeThisReferenceExpression(),
string.Format("On{0}", progressEventAttribute.EventName)),
new CodeArgumentReferenceExpression(progressPercentageParam.Name));
switch (intermediateResultsType.Members.Count)
{
case 0:
break;
case 1:
sendOrPostProgressInvocation.Parameters.Add(new CodeArgumentReferenceExpression(intermediateResultsType.Members[0].Name));
break;
default:
sendOrPostProgressInvocation.Parameters.Add(new CodeVariableReferenceExpression("results"));
break;
}
if (taskIDParam != null)
{
sendOrPostProgressInvocation.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
implementationMethod.Statements.Add(sendOrPostProgressInvocation);
if (cancelFlag != null)
{
CodeMethodInvokeExpression isOperationCancelledInvocation = new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(), "IsOperationCancelled");
if (taskIDParam != null)
{
isOperationCancelledInvocation.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
if (cancelFlag.IsRetval || string.IsNullOrEmpty(cancelFlag.Name))
{
implementationMethod.Statements.Add(
new CodeMethodReturnStatement(
isOperationCancelledInvocation));
}
else
{
implementationMethod.Statements.Add(
new CodeAssignStatement(
new CodeArgumentReferenceExpression(cancelFlag.Name),
isOperationCancelledInvocation));
}
}
}
private static void IdentifySpecialCallbackParameters(ref ParameterInfo progressPercentageParam, ref ParameterInfo taskIDParam, ref ParameterInfo cancelFlag, ParameterInfo interfaceParam)
{
object[] progressPercentageAttributes = interfaceParam.GetCustomAttributes(typeof(ProgressPercentageAttribute), false);
object[] userStateAttributes = interfaceParam.GetCustomAttributes(typeof(TaskIDAttribute), false);
object[] cancelFlagAttributes = interfaceParam.GetCustomAttributes(typeof(CancelFlagAttribute), false);
if (progressPercentageAttributes.Length > 0)
{
progressPercentageParam = interfaceParam;
}
if (userStateAttributes.Length > 0)
{
taskIDParam = interfaceParam;
}
if (cancelFlagAttributes.Length > 0)
{
cancelFlag = interfaceParam;
}
}
private static CodeMemberMethod MakeOnProgressChangedMethod(string progressEventName, CodeTypeDeclaration intermediateResultsType)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Attributes &= ~MemberAttributes.ScopeMask; // This makes it 'virtual.'
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Family;
value.Name = "On" + progressEventName;
value.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "args"));
value.Statements.Add(MakeOnProgressChangedMethodBody(progressEventName, intermediateResultsType));
return value;
}
private static CodeStatement MakeOnProgressChangedMethodBody(string progressEventName, CodeTypeDeclaration intermediateResultsType)
{
CodeDelegateInvokeExpression raiseProgressEvent = MakeRaiseProgressEventExpression(progressEventName, intermediateResultsType);
if (OutputLanguage.CS == outputLanguage)
{
CodeConditionStatement value = new CodeConditionStatement();
value.Condition = new CodeBinaryOperatorExpression(new CodeEventReferenceExpression(new CodeThisReferenceExpression(), progressEventName), CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null));
value.TrueStatements.Add(raiseProgressEvent);
return value;
}
else
{
return new CodeExpressionStatement(raiseProgressEvent);
}
}
private static CodeDelegateInvokeExpression MakeRaiseProgressEventExpression(string progressEventName, CodeTypeDeclaration intermediateResultsType)
{
CodeDelegateInvokeExpression value = new CodeDelegateInvokeExpression();
value.TargetObject = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), progressEventName);
value.Parameters.Add(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "client"));
value.Parameters.Add(new CodeCastExpression(MakeEventArgsOrHandlerType(intermediateResultsType, false, true), new CodeArgumentReferenceExpression("args")));
return value;
}
private static CodeMemberMethod MakeCallbackMethodSkeleton(Type callbackInterface, MethodInfo interfaceMethod)
{
CodeMemberMethod implementationMethod = new CodeMemberMethod();
implementationMethod.Attributes &= ~MemberAttributes.AccessMask;
if (OutputLanguage.CS == outputLanguage)
{
implementationMethod.Name = callbackInterface.Name + "." + interfaceMethod.Name;
}
else
{
implementationMethod.Attributes |= MemberAttributes.Public;
implementationMethod.Name = interfaceMethod.Name;
}
implementationMethod.ReturnType = new CodeTypeReference(interfaceMethod.ReturnType);
implementationMethod.ImplementationTypes.Add(callbackInterface);
foreach (ParameterInfo interfaceParam in interfaceMethod.GetParameters())
{
implementationMethod.Parameters.Add(MakeParameterDeclaration(interfaceParam));
}
return implementationMethod;
}
private static CodeMemberMethod MakeTrackerCompletionEventHandler(string eventName, string trackerFieldName, CodeTypeDeclaration outputType)
{
return MakeTrackerEventHandler(eventName, trackerFieldName + "_OperationCompleted", MakeEventArgsOrHandlerType(outputType, true, true));
}
private static CodeMemberMethod MakeTrackerProgressEventHandler(string eventName, string trackerFieldName, CodeTypeDeclaration outputType)
{
return MakeTrackerEventHandler(eventName, trackerFieldName + "_" + eventName, MakeEventArgsOrHandlerType(outputType, false, true));
}
private static CodeMemberMethod MakeTrackerEventHandler(string eventName, string eventHandlerName, CodeTypeReference eventArgsType)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Name = eventHandlerName;
value.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
value.Parameters.Add(new CodeParameterDeclarationExpression(eventArgsType, "args"));
CodeDelegateInvokeExpression raiseEventExpression = new CodeDelegateInvokeExpression();
raiseEventExpression.TargetObject = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), eventName);
raiseEventExpression.Parameters.Add(new CodeThisReferenceExpression());
raiseEventExpression.Parameters.Add(new CodeArgumentReferenceExpression("args"));
if (OutputLanguage.CS == outputLanguage)
{
CodeConditionStatement raiseEventIfNotNullStatement = new CodeConditionStatement();
CodeBinaryOperatorExpression eventNotNull = new CodeBinaryOperatorExpression();
eventNotNull.Operator = CodeBinaryOperatorType.IdentityInequality;
eventNotNull.Left = new CodeEventReferenceExpression(new CodeThisReferenceExpression(), eventName);
eventNotNull.Right = new CodePrimitiveExpression(null);
raiseEventIfNotNullStatement.Condition = eventNotNull;
raiseEventIfNotNullStatement.TrueStatements.Add(raiseEventExpression);
value.Statements.Add(raiseEventIfNotNullStatement);
}
else
{
value.Statements.Add(new CodeExpressionStatement(raiseEventExpression));
}
return value;
}
private static CodeAttachEventStatement MakeAttachTrackerCompletedEventStatement(string trackerFieldName, string eventName, CodeTypeDeclaration outputType)
{
return MakeAttachTrackerEventStatement(trackerFieldName, eventName, MakeEventArgsOrHandlerType(outputType, true, false));
}
private static CodeAttachEventStatement MakeAttachTrackerProgressEventStatement(string trackerFieldName, string eventName, CodeTypeDeclaration resultsType)
{
return MakeAttachTrackerEventStatement(trackerFieldName, eventName, MakeEventArgsOrHandlerType(resultsType, false, false));
}
private static CodeAttachEventStatement MakeAttachTrackerEventStatement(string trackerFieldName, string eventName, CodeTypeReference eventHandlerType)
{
CodeAttachEventStatement value = new CodeAttachEventStatement();
value.Event = new CodeEventReferenceExpression();
value.Event.TargetObject = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName);
value.Event.EventName = eventName;
value.Listener = new CodeDelegateCreateExpression(eventHandlerType, new CodeThisReferenceExpression(), trackerFieldName + "_" + eventName);
return value;
}
private static CodeMemberField MakeTrackerField(string trackerClassName, string trackerFieldName)
{
return new CodeMemberField(trackerClassName, trackerFieldName);
}
private static CodeTypeDeclaration MakeTrackerClass(MethodInfo originalMethod, CodeTypeDeclaration asyncClientClass, CodeConstructor clientCtor, string serverTypeName, string trackerClassName, string trackerFieldName, string delegateTypeName, CodeTypeDeclaration outputType, GenerateAsyncOperationAttribute asyncOperationAttribute)
{
CodeTypeDeclaration value = new CodeTypeDeclaration();
ParameterInfo taskIDParam = null;
foreach (ParameterInfo param in originalMethod.GetParameters())
{
object[] paramAttributes = param.GetCustomAttributes(typeof(TaskIDAttribute), false);
if (paramAttributes.Length > 0)
{
taskIDParam = param;
}
}
value.Name = trackerClassName;
value.TypeAttributes &= ~TypeAttributes.VisibilityMask;
value.TypeAttributes |= TypeAttributes.NestedPrivate;
CodeTypeReference baseType = new CodeTypeReference("OperationTracker", new CodeTypeReference(serverTypeName), new CodeTypeReference(asyncClientClass.Name), new CodeTypeReference(delegateTypeName));
if (outputType.Members.Count > 0)
{
baseType.TypeArguments.Add(outputType.Name);
}
value.BaseTypes.Add(baseType);
value.Members.Add(MakeTrackerConstructor(serverTypeName, asyncClientClass.Name));
value.Members.Add(MakeTrackerCallEndInvokeMethod(originalMethod, delegateTypeName, outputType));
if (asyncOperationAttribute.CallbackInterface != null)
{
value.BaseTypes.Add(new CodeTypeReference(asyncOperationAttribute.CallbackInterface));
ImplementCallbackInterface(asyncOperationAttribute.CallbackInterface, clientCtor, asyncClientClass, value, trackerFieldName, asyncOperationAttribute.BaseName);
}
return value;
}
private static CodeConstructor MakeTrackerConstructor(string serverTypeName, string clientTypeName)
{
CodeConstructor ctor = new CodeConstructor();
ctor.Attributes &= ~MemberAttributes.AccessMask;
ctor.Attributes |= MemberAttributes.Public;
ctor.Parameters.Add(new CodeParameterDeclarationExpression(serverTypeName, "server"));
ctor.Parameters.Add(new CodeParameterDeclarationExpression(clientTypeName, "client"));
ctor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("server"));
ctor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("client"));
return ctor;
}
private static CodeMemberMethod MakeTrackerCallEndInvokeMethod(MethodInfo originalMethod, string delegateTypeName, CodeTypeDeclaration outputType)
{
CodeMemberMethod value = MakeTrackerCallEndInvokeMethodSkeleton(delegateTypeName, outputType);
CodeMethodInvokeExpression methodInvocation = new CodeMethodInvokeExpression();
methodInvocation.Method = new CodeMethodReferenceExpression(new CodeArgumentReferenceExpression("d"), "EndInvoke");
foreach (ParameterInfo param in originalMethod.GetParameters())
{
if (param.ParameterType.IsByRef)
{
if (!param.IsOut)
{
// Ref param
value.Statements.Add(
new CodeAssignStatement(
MakeOutputArgumentReferenceExpression(outputType, param.Name),
new CodeDefaultValueExpression(new CodeTypeReference(param.ParameterType.FullName.TrimEnd('&')))));
}
methodInvocation.Parameters.Add(new CodeDirectionExpression(
param.IsOut ? FieldDirection.Out : FieldDirection.Ref,
MakeOutputArgumentReferenceExpression(outputType, param.Name)));
}
}
methodInvocation.Parameters.Add(new CodeArgumentReferenceExpression("iar"));
if (originalMethod.ReturnType == typeof(void))
{
value.Statements.Add(methodInvocation);
}
else
{
value.Statements.Add(new CodeAssignStatement(MakeOutputArgumentReferenceExpression(outputType, "_ReturnValue"), methodInvocation));
}
return value;
}
private static CodeExpression MakeOutputArgumentReferenceExpression(CodeTypeDeclaration outputType, string fieldName)
{
if (outputType.Members.Count == 1)
{
return new CodeArgumentReferenceExpression("output");
}
else
{
return new CodeFieldReferenceExpression(new CodeArgumentReferenceExpression("output"), fieldName);
}
}
private static CodeMemberMethod MakeTrackerCallEndInvokeMethodSkeleton(string delegateTypeName, CodeTypeDeclaration outputType)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Family;
value.Attributes &= ~MemberAttributes.ScopeMask;
value.Attributes |= MemberAttributes.Override;
value.ReturnType = new CodeTypeReference(typeof(void));
value.Name = "CallEndInvoke";
value.Parameters.Add(new CodeParameterDeclarationExpression(delegateTypeName, "d"));
value.Parameters.Add(new CodeParameterDeclarationExpression(typeof(IAsyncResult), "iar"));
if (outputType.Members.Count > 0)
{
CodeParameterDeclarationExpression outputParam = new CodeParameterDeclarationExpression(outputType.Name, "output");
outputParam.Direction = FieldDirection.Out;
value.Parameters.Add(outputParam);
}
return value;
}
private static CodeTypeDeclaration MakeOutputType(MethodInfo method, string typeName)
{
CodeTypeDeclaration value = new CodeTypeDeclaration();
value.Name = typeName;
value.IsStruct = true;
if (method.ReturnType != typeof(void))
{
CodeMemberField field = new CodeMemberField(method.ReturnType, "_ReturnValue");
field.Attributes &= ~MemberAttributes.AccessMask;
field.Attributes |= MemberAttributes.Public;
value.Members.Add(field);
}
foreach (ParameterInfo param in method.GetParameters())
{
if (param.ParameterType.IsByRef)
{
CodeMemberField field = new CodeMemberField(param.ParameterType.FullName.TrimEnd('&'), param.Name);
field.Attributes &= ~MemberAttributes.AccessMask;
field.Attributes |= MemberAttributes.Public;
value.Members.Add(field);
}
}
switch (value.Members.Count)
{
case 0:
value.Name = typeof(void).FullName;
break;
case 1:
CodeMemberField field = (CodeMemberField)value.Members[0];
value.Name = field.Type.BaseType;
break;
default:
break;
}
return value;
}
private static CodeTypeDeclaration MakeIntermediateResultsType(MethodInfo method, string typeName)
{
CodeTypeDeclaration value = new CodeTypeDeclaration();
value.Name = typeName;
value.IsStruct = true;
foreach (ParameterInfo param in method.GetParameters())
{
if (!param.IsOut && param.GetCustomAttributes(false).Length == 0)
{
string fieldTypeName = param.ParameterType.FullName;
CodeMemberField field = new CodeMemberField(param.ParameterType.IsByRef ? fieldTypeName.TrimEnd('&') : fieldTypeName, param.Name);
field.Attributes &= ~MemberAttributes.AccessMask;
field.Attributes |= MemberAttributes.Public;
value.Members.Add(field);
}
}
switch (value.Members.Count)
{
case 0:
value.Name = typeof(void).FullName;
break;
case 1:
CodeMemberField field = (CodeMemberField)value.Members[0];
value.Name = field.Type.BaseType;
break;
default:
break;
}
return value;
}
#if USE_SNIPPETS
private static CodeSnippetTypeMember MakeCompletionEvent(string completedEventName, string trackerFieldName, CodeTypeDeclaration outputType)
{
CodeSnippetTypeMember value = new CodeSnippetTypeMember();
value.Name = completedEventName;
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
string argsType = MakeEventArgsOrHandlerType("AsyncCompletedEventArgs", outputType);
string handlerType = MakeEventArgsOrHandlerType("AsyncCompletedEventHandler", outputType);
StringBuilder addAccessorBody, removeAccessorBody;
if (!addAccessorBodies.TryGetValue(completedEventName, out addAccessorBody))
{
addAccessorBody = new StringBuilder();
addAccessorBodies.Add(completedEventName, addAccessorBody);
}
if (!removeAccessorBodies.TryGetValue(completedEventName, out removeAccessorBody))
{
removeAccessorBody = new StringBuilder();
removeAccessorBodies.Add(completedEventName, removeAccessorBody);
}
value.Text =
MakeEventDeclarationStart(completedEventName, handlerType) +
MakeEventAccessor('+', handlerType, trackerFieldName, "OperationCompleted", addAccessorBody) +
MakeEventAccessor('-', handlerType, trackerFieldName, "OperationCompleted", removeAccessorBody) +
//MakeEventAccessor('^', handlerType, trackerFieldName, "OperationCompleted") +
MakeRaiseEventAccessor(argsType, completedEventName) +
MakeEventDeclarationEnd();
return value;
}
#else
private static CodeMemberEvent MakeCompletionEvent(string completedEventName, string trackerFieldName, CodeTypeDeclaration outputType)
{
CodeMemberEvent value = new CodeMemberEvent();
value.Name = completedEventName;
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
value.Type = MakeEventArgsOrHandlerType(outputType, true, false);
return value;
}
#endif
#if USE_SNIPPETS
private static CodeSnippetTypeMember MakeCustomProgressEvent(string progressEventName, string trackerFieldName, CodeTypeDeclaration intermediateResultsType)
{
CodeSnippetTypeMember value = new CodeSnippetTypeMember();
value.Name = progressEventName;
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
string handlerType = MakeEventArgsOrHandlerType("ProgressChangedEventHandler", intermediateResultsType);
string argsType = MakeEventArgsOrHandlerType("ProgressChangedEventArgs", intermediateResultsType);
StringBuilder addAccessorBody, removeAccessorBody;
if (!addAccessorBodies.TryGetValue(progressEventName, out addAccessorBody))
{
addAccessorBody = new StringBuilder();
addAccessorBodies.Add(progressEventName, addAccessorBody);
}
if (!removeAccessorBodies.TryGetValue(progressEventName, out removeAccessorBody))
{
removeAccessorBody = new StringBuilder();
removeAccessorBodies.Add(progressEventName, removeAccessorBody);
}
value.Text =
MakeEventDeclarationStart(progressEventName, handlerType) +
MakeEventAccessor('+', handlerType, trackerFieldName, progressEventName, addAccessorBody) +
MakeEventAccessor('-', handlerType, trackerFieldName, progressEventName, removeAccessorBody) +
//MakeEventAccessor('^', handlerType, trackerFieldName, progressEventName) +
MakeRaiseEventAccessor(argsType, progressEventName) +
MakeEventDeclarationEnd();
return value;
}
#endif
private static CodeMemberEvent MakeSimpleProgressEvent(string progressEventName, CodeTypeDeclaration intermediateResultsType)
{
CodeMemberEvent value = new CodeMemberEvent();
value.Name = progressEventName;
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
value.Type = MakeEventArgsOrHandlerType(intermediateResultsType, false, false);
return value;
}
#if USE_SNIPPETS
private static string MakeRaiseEventAccessor(string argsType, string eventName)
{
return string.Format(
OutputLanguage.VB == outputLanguage
// VB requires this accessor.
? "RaiseEvent(ByVal sender As Object, ByVal args As {0})\r\nDebug.Fail(\"The event {1} should not be raised directly.\")\r\nEnd RaiseEvent\r\n"
// C# doesn't support this accessor yet.
: string.Empty,
argsType, eventName);
}
private static string MakeEventAccessor(char op, string handlerType, string trackerFieldName, string eventName, StringBuilder accessorBody)
{
string verb = OutputLanguage.VB == outputLanguage
? (op == '+' ? "AddHandler" : op == '-' ? "RemoveHandler" : op == '^' ? "RaiseEvent" : null)
: (op == '+' ? "add" : op == '-' ? "remove" : op == '^' ? "raise" : null);
string accessorDeclarationStart = string.Format(
OutputLanguage.VB == outputLanguage
? "{0}(ByVal value As {1})\r\n"
: "{0} {{ ",
verb, handlerType);
accessorBody.AppendFormat(
OutputLanguage.VB == outputLanguage
? "{1} Me.{2}.{3}, value\r\n"
: "this.{2}.{3} {0}= value; ",
op, verb, trackerFieldName, eventName);
string accessorDeclarationEnd = string.Format(
OutputLanguage.VB == outputLanguage
? "End {0}\r\n"
: "}} ",
verb);
return accessorDeclarationStart + accessorBody + accessorDeclarationEnd;
}
private static string MakeEventDeclarationStart(string completedEventName, string handlerType)
{
return string.Format(
OutputLanguage.VB == outputLanguage
? "Public Custom Event {0} As {1}\r\n"
: "public event {1} {0} {{ ",
completedEventName, handlerType);
}
private static string MakeEventDeclarationEnd()
{
return (OutputLanguage.VB == outputLanguage ? "End Event" : "}");
}
private static string MakeEventArgsOrHandlerType(string baseTypeName, CodeTypeDeclaration typeArgument)
{
string value = baseTypeName;
if (typeArgument.Name != typeof(void).FullName)
{
value += string.Format(OutputLanguage.VB == outputLanguage ? "(Of {0})" : "<{0}>", typeArgument.Name);
}
return value;
}
#endif
private static CodeTypeReference MakeEventArgsOrHandlerType(CodeTypeDeclaration typeArgument, bool makeCompletionEvent, bool makeArgsType)
{
CodeTypeReference value = new CodeTypeReference(string.Format("{0}.{1}Event{2}",
typeArgument.Members.Count == 0 ? "System.ComponentModel" : "AsyncGen",
makeCompletionEvent ? "AsyncCompleted" : "ProgressChanged",
makeArgsType ? "Args" : "Handler"));
if (typeArgument.Members.Count > 0)
{
value.TypeArguments.Add(typeArgument.Name);
}
return value;
}
private static CodeConstructor MakeConstructorSkeleton()
{
CodeConstructor value = new CodeConstructor();
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
return value;
}
private static CodeMemberMethod MakeAsyncMethod(MethodInfo originalMethod, ParameterInfo taskIDParam, ICollection<ParameterInfo> specialParams, Type callbackInterface, string delegateTypeName, string methodName, string trackerFieldName)
{
CodeMemberMethod value = MakeAsyncMethodSkeleton(originalMethod, methodName, callbackInterface);
value.Statements.Add(MakeTrackerCreateOperationtMethodInvocation(originalMethod, trackerFieldName, taskIDParam));
foreach (ParameterInfo param in originalMethod.GetParameters())
{
if (param.IsOut)
{
value.Statements.Add(new CodeVariableDeclarationStatement(param.ParameterType.FullName.TrimEnd('&'), param.Name));
}
}
value.Statements.Add(MakeDelegateDeclaration(originalMethod, delegateTypeName));
value.Statements.Add(MakeBeginInvokeInvocation(originalMethod, trackerFieldName, taskIDParam, callbackInterface));
return value;
}
private static CodeMemberMethod MakeCancelMethod(MethodInfo originalMethod, string methodName, string trackerFieldName)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
value.Name = methodName;
value.ReturnType = new CodeTypeReference(typeof(void));
ParameterInfo taskIDParam = null;
foreach (ParameterInfo param in originalMethod.GetParameters())
{
object[] paramAttributes = param.GetCustomAttributes(typeof(TaskIDAttribute), false);
if (paramAttributes.Length > 0)
{
if (taskIDParam == null)
{
taskIDParam = param;
}
else
{
throw new ApplicationException("Only one parameter may have the [TaskID] attribute.");
}
}
}
if (taskIDParam != null)
{
value.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "userState"));
}
value.Statements.Add(MakeTrackerCancelOperationMethodInvocation(trackerFieldName, taskIDParam));
value.Statements.Add(new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException))));
return value;
}
private static CodeStatement MakeTrackerCancelOperationMethodInvocation(string trackerFieldName, ParameterInfo taskIDParam)
{
CodeMethodInvokeExpression invokeTrackerCancelOperation = new CodeMethodInvokeExpression();
invokeTrackerCancelOperation.Method.TargetObject = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName);
invokeTrackerCancelOperation.Method.MethodName = "TryCancelOperation";
if (taskIDParam != null)
{
invokeTrackerCancelOperation.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
return new CodeConditionStatement(invokeTrackerCancelOperation, new CodeMethodReturnStatement());
}
private static CodeVariableDeclarationStatement MakeDelegateDeclaration(MethodInfo originalMethod, string delegateTypeName)
{
CodeVariableDeclarationStatement value = new CodeVariableDeclarationStatement();
value.Type = new CodeTypeReference(delegateTypeName);
value.Name = "d";
CodeDelegateCreateExpression delegateCreation = new CodeDelegateCreateExpression();
delegateCreation.DelegateType = new CodeTypeReference(delegateTypeName);
delegateCreation.TargetObject = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "server");
#if !USE_SNIPPETS
if (OutputLanguage.CPP == outputLanguage)
{
// The CppCodeProvider needs to be reminded of the type of the 'server' field, or it will emit bad code.
delegateCreation.TargetObject = new CodeCastExpression(new CodeTypeReference(originalMethod.DeclaringType), delegateCreation.TargetObject);
}
#endif
delegateCreation.MethodName = originalMethod.Name;
value.InitExpression = delegateCreation;
return value;
}
private static CodeMethodInvokeExpression MakeBeginInvokeInvocation(MethodInfo originalMethod, string trackerFieldName, ParameterInfo taskIDParam, Type callbackInterface)
{
CodeMethodInvokeExpression value = new CodeMethodInvokeExpression();
value.Method.TargetObject = new CodeVariableReferenceExpression("d");
value.Method.MethodName = "BeginInvoke";
foreach (ParameterInfo param in originalMethod.GetParameters())
{
value.Parameters.Add(
param.ParameterType == callbackInterface
? (CodeExpression)new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName)
: (CodeExpression)MakeInvocationArgument(param));
}
CodeDelegateCreateExpression trackerAsyncCallbackDelegate = new CodeDelegateCreateExpression();
trackerAsyncCallbackDelegate.DelegateType = new CodeTypeReference(typeof(AsyncCallback));
trackerAsyncCallbackDelegate.TargetObject = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName);
trackerAsyncCallbackDelegate.MethodName = "PostOperationCompleted";
value.Parameters.Add(trackerAsyncCallbackDelegate);
value.Parameters.Add(
taskIDParam == null
? (CodeExpression)new CodePrimitiveExpression(null)
: (CodeExpression)new CodeArgumentReferenceExpression(taskIDParam.Name));
return value;
}
private static CodeExpressionStatement MakeTrackerCreateOperationtMethodInvocation(MethodInfo originalMethod, string trackerFieldName, ParameterInfo taskIDParam)
{
CodeMethodInvokeExpression value = new CodeMethodInvokeExpression();
value.Method = new CodeMethodReferenceExpression(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), trackerFieldName), "CreateOperation");
if (taskIDParam != null)
{
value.Parameters.Add(new CodeArgumentReferenceExpression(taskIDParam.Name));
}
return new CodeExpressionStatement(value);
}
private static CodeMemberMethod MakeAsyncMethodSkeleton(MethodInfo originalMethod, string asyncMethodName, Type callbackInterface)
{
CodeMemberMethod value = new CodeMemberMethod();
value.Attributes &= ~MemberAttributes.AccessMask;
value.Attributes |= MemberAttributes.Public;
value.Name = asyncMethodName;
value.ReturnType = new CodeTypeReference(typeof(void));
foreach (ParameterInfo param in originalMethod.GetParameters())
{
CodeParameterDeclarationExpression paramDeclaration = MakeParameterDeclaration(param);
if (!param.IsOut && param.ParameterType != callbackInterface)
{
paramDeclaration.Direction = FieldDirection.In;
value.Parameters.Add(paramDeclaration);
}
}
return value;
}
private static CodeTypeDelegate MakeDelegateType(MethodInfo originalMethod, string delegateTypeName)
{
CodeTypeDelegate value = new CodeTypeDelegate(delegateTypeName);
value.TypeAttributes &= ~TypeAttributes.VisibilityMask;
value.TypeAttributes |= TypeAttributes.NestedPrivate;
value.ReturnType = new CodeTypeReference(originalMethod.ReturnType);
foreach (ParameterInfo param in originalMethod.GetParameters())
{
CodeParameterDeclarationExpression paramDeclaration = new CodeParameterDeclarationExpression(param.ParameterType.FullName.TrimEnd('&'), param.Name);
paramDeclaration.Direction = !param.ParameterType.IsByRef ? FieldDirection.In : param.IsOut ? FieldDirection.Out : FieldDirection.Ref;
value.Parameters.Add(paramDeclaration);
}
return value;
}
private static CodeDirectionExpression MakeInvocationArgument(ParameterInfo param)
{
CodeDirectionExpression value = new CodeDirectionExpression();
value.Expression = new CodeArgumentReferenceExpression(param.Name);
value.Direction = param.IsOut ? FieldDirection.Out : param.ParameterType.IsByRef ? FieldDirection.Ref : FieldDirection.In;
return value;
}
private static CodeParameterDeclarationExpression MakeParameterDeclaration(ParameterInfo param)
{
CodeParameterDeclarationExpression value = new CodeParameterDeclarationExpression(param.ParameterType.FullName.TrimEnd('&'), param.Name);
value.Direction = param.IsOut ? FieldDirection.Out : param.ParameterType.IsByRef ? FieldDirection.Ref : FieldDirection.In;
return value;
}
private static void AddNewMember(CodeTypeDeclaration typeDecl, CodeTypeMember newMember)
{
foreach (CodeTypeMember member in typeDecl.Members)
{
if (member.Name == newMember.Name)
{
typeDecl.Members.Remove(member);
typeDecl.Members.Add(newMember);
return;
}
}
typeDecl.Members.Add(newMember);
}
private static void GenerateCode(CodeCompileUnit compileUnit, CodeDomProvider provider, string sourceFileName)
{
CodeGeneratorOptions opt = new CodeGeneratorOptions();
opt.BracingStyle = "C";
using (TextWriter tw = new StreamWriter(sourceFileName))
{
provider.GenerateCodeFromCompileUnit(compileUnit, tw, opt);
}
provider.GenerateCodeFromCompileUnit(compileUnit, Console.Out, opt);
}
private static void CompileGeneratedCode(List<string> assemblies, CodeDomProvider provider, string sourceFileName)
{
string[] allAssemblies = new string[2 + assemblies.Count];
allAssemblies[0] = "System.dll";
allAssemblies[1] = "AsyncGenLib.dll";
assemblies.CopyTo(allAssemblies, 2);
CompilerParameters cp = new CompilerParameters(allAssemblies);
cp.GenerateInMemory = true;
cp.TreatWarningsAsErrors = true;
cp.WarningLevel = 4;
try
{
CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceFileName);
foreach (CompilerError error in cr.Errors)
{
Console.Error.WriteLine(error);
}
}
catch (NotImplementedException ex)
{
Console.Error.WriteLine("Can't compile the generated code: {0}", ex.Message);
}
}
#if USE_SNIPPETS
private static Dictionary<string, StringBuilder> addAccessorBodies = new Dictionary<string, StringBuilder>();
private static Dictionary<string, StringBuilder> removeAccessorBodies = new Dictionary<string, StringBuilder>();
#endif
private static CodeDomProvider codeDomProvider = null;
private static OutputLanguage outputLanguage = OutputLanguage.CS;
private enum OutputLanguage
{
CS = 0,
VB,
#if !USE_SNIPPETS
CPP,
#endif
}
}
}