private void GeneratePayloadCode( Type type, CodeWriter.CodeWriter w, List<Tuple<MethodInfo, Tuple<string, string>>> method2PayloadTypeNames) { var tagName = Utility.GetActorInterfaceTagName(type); w._($"[PayloadTable(typeof({type.GetSymbolDisplay(typeless: true)}), PayloadTableKind.Request)]"); using (w.B($"public static class {Utility.GetPayloadTableClassName(type)}{type.GetGenericParameters()}{type.GetGenericConstraintClause()}")) { // generate GetPayloadTypes method using (w.B("public static Type[,] GetPayloadTypes()")) { using (w.i("return new Type[,] {", "};")) { foreach (var m in method2PayloadTypeNames) { var genericParameters = m.Item1.GetGenericParameters(typeless: true); var payloadTypes = m.Item2; var returnType = payloadTypes.Item2 != "" ? $"typeof({payloadTypes.Item2}{genericParameters})" : "null"; w._($"{{ typeof({payloadTypes.Item1}{genericParameters}), {returnType} }},"); } } } // generate payload classes for all methods foreach (var m in method2PayloadTypeNames) { var method = m.Item1; var payloadTypes = m.Item2; var returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault(); var observerParameters = method.GetParameters() .Select(p => Tuple.Create(p, Utility.GetReachableMemebers(p.ParameterType, Utility.IsObserverInterface).ToArray())) .Where(i => i.Item2.Length > 0) .ToArray(); // Invoke payload if (Options.UseProtobuf) w._("[ProtoContract, TypeAlias]"); var tagOverridable = tagName != null ? ", IPayloadTagOverridable" : ""; var observerUpdatable = observerParameters.Any() ? ", IPayloadObserverUpdatable" : ""; using (w.B($"public class {payloadTypes.Item1}{method.GetGenericParameters()}", $": IInterfacedPayload, IAsyncInvokable{tagOverridable}{observerUpdatable}{method.GetGenericConstraintClause()}")) { // Parameters var parameters = method.GetParameters(); for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var attr = ""; var defaultValueExpression = ""; if (Options.UseProtobuf) { var defaultValueAttr = parameter.HasNonTrivialDefaultValue() ? $", DefaultValue({parameter.DefaultValue.GetValueLiteral()})" : ""; attr = $"[ProtoMember({i + 1}){defaultValueAttr}] "; if (parameter.HasNonTrivialDefaultValue()) { defaultValueExpression = " = " + parameter.DefaultValue.GetValueLiteral(); } } var typeName = parameter.ParameterType.GetSymbolDisplay(true); w._($"{attr}public {typeName} {parameter.Name}{defaultValueExpression};"); } if (parameters.Any()) w._(); // GetInterfaceType using (w.B($"public Type GetInterfaceType()")) { w._($"return typeof({type.GetSymbolDisplay()});"); } // InvokeAsync if (Options.UseSlimClient) { using (w.B("public Task<IValueGetable> InvokeAsync(object __target)")) { w._("return null;"); } } else { using (w.B("public async Task<IValueGetable> InvokeAsync(object __target)")) { var parameterNames = string.Join(", ", method.GetParameters().Select(p => p.Name)); if (returnType != null) { w._($"var __v = await (({type.GetSymbolDisplay()})__target).{method.Name}{method.GetGenericParameters()}({parameterNames});", $"return (IValueGetable)(new {payloadTypes.Item2}{method.GetGenericParameters()} {{ v = __v }});"); } else { w._($"await (({type.GetSymbolDisplay()})__target).{method.Name}{method.GetGenericParameters()}({parameterNames});", $"return null;"); } } } // IPayloadTagOverridable.SetTag if (tagName != null) { using (w.B($"void IPayloadTagOverridable.SetTag(object value)")) { var tagParameter = parameters.FirstOrDefault(pi => pi.Name == tagName); if (tagParameter != null) { var typeName = tagParameter.ParameterType.GetSymbolDisplay(true); w._($"{tagName} = ({typeName})value;"); } } } // IPayloadObserverUpdatable.Update if (observerParameters.Any()) { using (w.B("void IPayloadObserverUpdatable.Update(Action<IInterfacedObserver> updater)")) { foreach (var p in observerParameters) { using (w.b($"if ({p.Item1.Name} != null)")) { foreach (var o in p.Item2) { if (o == "") w._($"updater({p.Item1.Name});"); else w._($"if ({p.Item1.Name}.{o} != null) updater({p.Item1.Name}.{o});"); } } } } } } // Return payload if (returnType != null) { var actorRefs = Utility.GetReachableMemebers(returnType, Utility.IsActorInterface).ToArray(); if (Options.UseProtobuf) w._("[ProtoContract, TypeAlias]"); var actorRefUpdatable = actorRefs.Any() ? ", IPayloadActorRefUpdatable" : ""; using (w.B($"public class {payloadTypes.Item2}{method.GetGenericParameters()}", $": IInterfacedPayload, IValueGetable{actorRefUpdatable}{method.GetGenericConstraintClause()}")) { var attr = (Options.UseProtobuf) ? "[ProtoMember(1)] " : ""; w._($"{attr}public {returnType.GetSymbolDisplay(true)} v;"); w._(); // GetInterfaceType using (w.B("public Type GetInterfaceType()")) { w._($"return typeof({type.GetSymbolDisplay()});"); } // IValueGetable.Value using (w.B("public object Value")) { w._($"get {{ return v; }}"); } // IPayloadActorRefUpdatable.Update if (actorRefs.Any()) { using (w.B("void IPayloadActorRefUpdatable.Update(Action<object> updater)")) { using (w.b($"if (v != null)")) { foreach (var r in actorRefs) { if (r == "") w._($"updater(v); "); else w._($"if (v.{r} != null) updater(v.{r});"); } } } } } } } } }
private void GenerateSyncCode( Type type, CodeWriter.CodeWriter w, Type[] baseTypes, Tuple<Type, List<Tuple<MethodInfo, Tuple<string, string>>>>[] typeInfos) { // NoReply Interface var baseSynces = baseTypes.Select(t => Utility.GetActorSyncInterfaceName(t)); var baseSyncesInherit = baseSynces.Any() ? string.Join(", ", baseSynces) : "IInterfacedActorSync"; w._($"[AlternativeInterface(typeof({type.GetSymbolDisplay(typeless: true)}))]"); using (w.B($"public interface {Utility.GetActorSyncInterfaceName(type)}{type.GetGenericParameters()} : {baseSyncesInherit}{type.GetGenericConstraintClause()}")) { foreach (var m in typeInfos.First().Item2) { var method = m.Item1; var parameters = method.GetParameters(); var paramStr = string.Join(", ", parameters.Select(p => p.GetParameterDeclaration(true))); var returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault(); var returnTypeLiteral = (returnType != null) ? returnType.GetSymbolDisplay(true) : "void"; w._($"{returnTypeLiteral} {method.Name}{method.GetGenericParameters()}({paramStr}){method.GetGenericConstraintClause()};"); } } }
private void GeneratePayloadCode( Type type, CodeWriter.CodeWriter w, List<Tuple<MethodInfo, string>> method2PayloadTypeNames) { w._($"[PayloadTable(typeof({type.GetSymbolDisplay(typeless: true)}), PayloadTableKind.Notification)]"); using (w.B($"public static class {Utility.GetPayloadTableClassName(type)}{type.GetGenericParameters()}{type.GetGenericConstraintClause()}")) { // generate GetPayloadTypes method using (w.B("public static Type[] GetPayloadTypes()")) { using (w.i("return new Type[] {", "};")) { foreach (var m in method2PayloadTypeNames) { var genericParameters = m.Item1.GetGenericParameters(typeless: true); w._($"typeof({m.Item2}{genericParameters}),"); } } } // generate payload classes for all methods foreach (var m in method2PayloadTypeNames) { var method = m.Item1; var payloadTypeName = m.Item2; // Invoke payload if (Options.UseProtobuf) w._("[ProtoContract, TypeAlias]"); using (w.B($"public class {payloadTypeName}{method.GetGenericParameters()} : IInterfacedPayload, IInvokable{method.GetGenericConstraintClause()}")) { // Parameters var parameters = method.GetParameters(); for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; var attr = ""; var defaultValueExpression = ""; if (Options.UseProtobuf) { var defaultValueAttr = parameter.HasNonTrivialDefaultValue() ? $", DefaultValue({parameter.DefaultValue.GetValueLiteral()})" : ""; attr = $"[ProtoMember({i + 1}){defaultValueAttr}] "; if (parameter.HasNonTrivialDefaultValue()) { defaultValueExpression = " = " + parameter.DefaultValue.GetValueLiteral(); } } var typeName = parameter.ParameterType.GetSymbolDisplay(true); w._($"{attr}public {typeName} {parameter.Name}{defaultValueExpression};"); } if (parameters.Any()) w._(); // GetInterfaceType using (w.B("public Type GetInterfaceType()")) { w._($"return typeof({type.GetSymbolDisplay()});"); } // Invoke using (w.B("public void Invoke(object __target)")) { var parameterNames = string.Join(", ", method.GetParameters().Select(p => p.Name)); w._($"(({type.GetSymbolDisplay()})__target).{method.Name}{method.GetGenericParameters()}({parameterNames});"); } } } } }
private void GenerateRefCode( Type type, CodeWriter.CodeWriter w, Type[] baseTypes, Tuple<Type, List<Tuple<MethodInfo, Tuple<string, string>>>>[] typeInfos) { // NoReply Interface var baseNoReplys = baseTypes.Select(t => Utility.GetNoReplyInterfaceName(t)); var baseNoReplysInherit = baseNoReplys.Any() ? " : " + string.Join(", ", baseNoReplys) : ""; using (w.B($"public interface {Utility.GetNoReplyInterfaceName(type)}{type.GetGenericParameters()}{baseNoReplysInherit}{type.GetGenericConstraintClause()}")) { foreach (var m in typeInfos.First().Item2) { var method = m.Item1; var parameters = method.GetParameters(); var paramStr = string.Join(", ", parameters.Select(p => p.GetParameterDeclaration(true))); w._($"void {method.Name}{method.GetGenericParameters()}({paramStr}){method.GetGenericConstraintClause()};"); } } // ActorRef var refClassName = Utility.GetActorRefClassName(type); var refClassGenericName = refClassName + type.GetGenericParameters(); var noReplyInterfaceName = Utility.GetNoReplyInterfaceName(type); var noReplyInterfaceGenericName = noReplyInterfaceName + type.GetGenericParameters(); using (w.B($"public class {refClassName}{type.GetGenericParameters()} : InterfacedActorRef, {type.GetSymbolDisplay()}, {noReplyInterfaceName}{type.GetGenericParameters()}{type.GetGenericConstraintClause()}")) { // InterfaceType property w._($"public override Type InterfaceType => typeof({type.GetSymbolDisplay()});"); w._(); // Constructors using (w.B($"public {refClassName}() : base(null)")) { } using (w.B($"public {refClassName}(IRequestTarget target) : base(target)")) { } using (w.B($"public {refClassName}(IRequestTarget target, IRequestWaiter requestWaiter, TimeSpan? timeout = null) : base(target, requestWaiter, timeout)")) { } // With Helpers using (w.B($"public {noReplyInterfaceGenericName} WithNoReply()")) { w._("return this;"); } using (w.B($"public {refClassGenericName} WithRequestWaiter(IRequestWaiter requestWaiter)")) { w._($"return new {refClassGenericName}(Target, requestWaiter, Timeout);"); } using (w.B($"public {refClassGenericName} WithTimeout(TimeSpan? timeout)")) { w._($"return new {refClassGenericName}(Target, RequestWaiter, timeout);"); } // IInterface message methods foreach (var t in typeInfos) { var payloadTableClassName = Utility.GetPayloadTableClassName(t.Item1) + type.GetGenericParameters(); foreach (var m in t.Item2) { var method = m.Item1; var payloadTypes = m.Item2; var parameters = method.GetParameters(); var parameterTypeNames = string.Join(", ", parameters.Select(p => p.GetParameterDeclaration(true))); var parameterInits = string.Join(", ", parameters.Select(Utility.GetParameterAssignment)); var returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault(); // Request Methods var returnTaskType = (returnType != null) ? $"Task<{returnType.GetSymbolDisplay(true)}>" : "Task"; var prototype = $"public {returnTaskType} {method.Name}{method.GetGenericParameters()}({parameterTypeNames}){method.GetGenericConstraintClause()}"; using (w.B(prototype)) { using (w.i("var requestMessage = new RequestMessage {", "};")) { w._($"InvokePayload = new {payloadTableClassName}.{payloadTypes.Item1}{method.GetGenericParameters()} {{ {parameterInits} }}"); } if (returnType != null) w._($"return SendRequestAndReceive<{returnType.GetSymbolDisplay(true)}>(requestMessage);"); else w._($"return SendRequestAndWait(requestMessage);"); } } } // IInterface_NoReply message methods foreach (var t in typeInfos) { var interfaceName = Utility.GetNoReplyInterfaceName(t.Item1); var interfaceGenericName = interfaceName + t.Item1.GetGenericParameters(); var payloadTableClassName = Utility.GetPayloadTableClassName(t.Item1) + type.GetGenericParameters(); foreach (var m in t.Item2) { var method = m.Item1; var payloadTypes = m.Item2; var parameters = method.GetParameters(); var parameterTypeNames = string.Join(", ", parameters.Select(p => p.GetParameterDeclaration(false))); var parameterInits = string.Join(", ", parameters.Select(Utility.GetParameterAssignment)); // Request Methods using (w.B($"void {interfaceGenericName}.{method.Name}{method.GetGenericParameters()}({parameterTypeNames})")) { using (w.i("var requestMessage = new RequestMessage {", "};")) { w._($"InvokePayload = new {payloadTableClassName}.{payloadTypes.Item1}{method.GetGenericParameters()} {{ {parameterInits} }}"); } w._("SendRequest(requestMessage);"); } } } } // Protobuf-net specialized if (Options.UseProtobuf) { var surrogateClassName = Utility.GetSurrogateClassName(type); w._("[ProtoContract]"); using (w.B($"public class {surrogateClassName}")) { w._($"[ProtoMember(1)] public IRequestTarget Target;"); w._(); w._("[ProtoConverter]"); using (w.B($"public static {surrogateClassName} Convert({type.Name} value)")) { w._($"if (value == null) return null;"); w._($"return new {surrogateClassName} {{ Target = (({refClassName})value).Target }};"); } w._("[ProtoConverter]"); using (w.B($"public static {type.Name} Convert({surrogateClassName} value)")) { w._($"if (value == null) return null;"); w._($"return new {refClassName}(value.Target);"); } } } }
private void GenerateObserverCode( Type type, CodeWriter.CodeWriter w, Type[] baseTypes, Tuple<Type, List<Tuple<MethodInfo, string>>>[] typeInfos) { var className = Utility.GetObserverClassName(type); using (w.B($"public class {className}{type.GetGenericParameters()} : InterfacedObserver, {type.GetSymbolDisplay()}{type.GetGenericConstraintClause()}")) { // Constructor using (w.B($"public {className}()", $": base(null, 0)")) { } // Constructor (INotificationChannel) using (w.B($"public {className}(INotificationChannel channel, int observerId = 0)", $": base(channel, observerId)")) { } // Observer method messages foreach (var t in typeInfos) { var payloadTableClassName = Utility.GetPayloadTableClassName(t.Item1) + type.GetGenericParameters(); foreach (var m in t.Item2) { var method = m.Item1; var payloadType = m.Item2; var parameters = method.GetParameters(); var parameterNames = string.Join(", ", parameters.Select(p => p.Name)); var parameterTypeNames = string.Join(", ", parameters.Select(p => (p.GetCustomAttribute<ParamArrayAttribute>() != null ? "params " : "") + p.ParameterType.GetSymbolDisplay(true) + " " + p.Name)); var parameterInits = string.Join(", ", parameters.Select(Utility.GetParameterAssignment)); // Request Methods using (w.B($"public void {method.Name}{method.GetGenericParameters()}({parameterTypeNames}){method.GetGenericConstraintClause()}")) { w._($"var payload = new {payloadTableClassName}.{payloadType}{method.GetGenericParameters()} {{ {parameterInits} }};", $"Notify(payload);"); } } } } // Protobuf-net specialized if (Options.UseProtobuf) { var surrogateClassName = Utility.GetSurrogateClassName(type); w._("[ProtoContract]"); using (w.B($"public class {surrogateClassName}")) { w._("[ProtoMember(1)] public INotificationChannel Channel;"); w._("[ProtoMember(2)] public int ObserverId;"); w._(); w._("[ProtoConverter]"); using (w.B($"public static {surrogateClassName} Convert({type.Name} value)")) { w._($"if (value == null) return null;"); w._($"var o = ({className})value;"); w._($"return new {surrogateClassName} {{ Channel = o.Channel, ObserverId = o.ObserverId }};"); } w._("[ProtoConverter]"); using (w.B($"public static {type.Name} Convert({surrogateClassName} value)")) { w._($"if (value == null) return null;"); w._($"return new {className}(value.Channel, value.ObserverId);"); } } } }