protected virtual CodeTypeDeclaration GetStateClass( GrainInterfaceData grainInterfaceData, Action <Type> referred, string stateClassBaseName, string stateClassName, out bool hasStateClass) { var sourceType = grainInterfaceData.Type; stateClassName = FixupTypeName(stateClassName); CodeTypeParameterCollection genericTypeParams = grainInterfaceData.GenericTypeParams; Func <Type, bool> nonamespace = t => CurrentNamespace == t.Namespace || ReferencedNamespaces.Contains(t.Namespace); Type persistentInterface = GetPersistentInterface(sourceType); Dictionary <string, PropertyInfo> asyncProperties = GrainInterfaceData.GetPersistentProperties(persistentInterface) .ToDictionary(p => p.Name.Substring(p.Name.LastIndexOf('.') + 1), p => p); Dictionary <string, string> properties = asyncProperties.ToDictionary(p => p.Key, p => GetGenericTypeName(GrainInterfaceData.GetPromptType(p.Value.PropertyType), referred, nonamespace)); var stateClass = new CodeTypeDeclaration(stateClassBaseName); if (genericTypeParams != null) { stateClass.TypeParameters.AddRange(genericTypeParams); } stateClass.IsClass = true; if (persistentInterface != null) { stateClass.TypeAttributes = persistentInterface.IsPublic ? TypeAttributes.Public : TypeAttributes.NotPublic; } else { stateClass.TypeAttributes = TypeAttributes.Public; } stateClass.BaseTypes.Add(new CodeTypeReference(typeof(GrainState), CodeTypeReferenceOptions.GlobalReference)); MarkAsGeneratedCode(stateClass); referred(typeof(GrainState)); if (persistentInterface != null) { stateClass.BaseTypes.Add(new CodeTypeReference(GetGenericTypeName(persistentInterface, referred, nonamespace))); } stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(SerializableAttribute).Name)); stateClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(GrainStateAttribute), CodeTypeReferenceOptions.GlobalReference), new CodeAttributeArgument(new CodePrimitiveExpression(grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type))))); referred(typeof(SerializableAttribute)); referred(typeof(OnDeserializedAttribute)); var initStateFields = new CodeMemberMethod { Name = "InitStateFields" }; initStateFields.Attributes = (initStateFields.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private; foreach (var peoperty in asyncProperties) { Type propertyType = peoperty.Value.PropertyType; bool noCreateNew = propertyType.IsPrimitive || typeof(string).IsAssignableFrom(propertyType) || // Primative types propertyType.IsAbstract || propertyType.IsInterface || propertyType.IsGenericParameter || // No concrete implementation propertyType.GetConstructor(Type.EmptyTypes) == null; // No default constructor var initExpression = noCreateNew // Pre-initialize this type to default value ? (CodeExpression) new CodeDefaultValueExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace))) : new CodeObjectCreateExpression(new CodeTypeReference(GetGenericTypeName(propertyType, referred, nonamespace))); initStateFields.Statements.Add(new CodeAssignStatement( new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), peoperty.Key), initExpression)); } hasStateClass = properties.Count > 0; if (hasStateClass) { foreach (var pair in properties) { GenerateStateClassProperty(stateClass, asyncProperties[pair.Key], pair.Key, pair.Value); } var returnType = new CodeTypeReference("System.Collections.Generic.IDictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object))); var concreteType = new CodeTypeReference("System.Collections.Generic.Dictionary", new CodeTypeReference(typeof(string)), new CodeTypeReference(typeof(object))); var asDictionary = new CodeMemberMethod { Name = "AsDictionary", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = returnType }; asDictionary.Statements.Add(new CodeVariableDeclarationStatement(concreteType, "result", new CodeObjectCreateExpression(concreteType))); foreach (var pair in properties) { asDictionary.Statements.Add(new CodeAssignStatement( new CodeIndexerExpression(new CodeVariableReferenceExpression("result"), new CodePrimitiveExpression(pair.Key)), new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), pair.Key))); } asDictionary.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("result"))); stateClass.Members.Add(asDictionary); GenerateSetAll(stateClass, properties); GenerateToString(stateClass, stateClassName, properties); } // Copier, serializer, and deserializer for the state class var copier = SerializerGenerationUtilities.GenerateCopier("_Copier", stateClassName, genericTypeParams); var serializer = SerializerGenerationUtilities.GenerateSerializer("_Serializer", stateClassName, genericTypeParams); var deserializer = SerializerGenerationUtilities.GenerateDeserializer("_Deserializer", stateClassName, genericTypeParams); var ctor = new CodeConstructor { Attributes = (copier.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public }; ctor.BaseConstructorArgs.Add(new CodePrimitiveExpression(TypeUtils.GetFullName(grainInterfaceData.Type))); ctor.Statements.Add(new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "InitStateFields")); copier.Statements.Add(new CodeMethodReturnStatement( new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("input"), "DeepCopy"))); serializer.Statements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("input"), "SerializeTo", new CodeArgumentReferenceExpression("stream"))); deserializer.Statements.Add(new CodeVariableDeclarationStatement(stateClassName, "result", new CodeObjectCreateExpression(stateClassName))); deserializer.Statements.Add(new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("result"), "DeserializeFrom", new CodeArgumentReferenceExpression("stream"))); deserializer.Statements.Add(new CodeMethodReturnStatement( new CodeVariableReferenceExpression("result"))); stateClass.Members.Add(ctor); stateClass.Members.Add(initStateFields); stateClass.Members.Add(copier); stateClass.Members.Add(serializer); stateClass.Members.Add(deserializer); return(stateClass); }
protected override CodeTypeDeclaration GetStateClass(GrainInterfaceData grainInterfaceData, Action <Type> referred, string stateClassBaseName, string stateClassName, out bool hasStateClass) { var sourceType = grainInterfaceData.Type; stateClassName = FixupTypeName(stateClassName); CodeTypeParameterCollection genericTypeParams = grainInterfaceData.GenericTypeParams; Func <Type, bool> nonamespace = t => false; Type persistentInterface = GetPersistentInterface(sourceType); Dictionary <string, PropertyInfo> asyncProperties = GrainInterfaceData.GetPersistentProperties(persistentInterface) .ToDictionary(p => p.Name.Substring(p.Name.LastIndexOf('.') + 1), p => p); Dictionary <string, string> properties = asyncProperties.ToDictionary(p => p.Key, p => GetGenericTypeName(GrainInterfaceData.GetPromptType(p.Value.PropertyType), referred, nonamespace)); hasStateClass = properties.Count > 0; if (!hasStateClass) { return(null); } var typeAccess = (persistentInterface != null && !persistentInterface.IsPublic) ? "internal" : "public"; StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<System.CodeDom.Compiler.GeneratedCodeAttribute(""{0}"", ""{1}"")>]", CODE_GENERATOR_NAME, CodeGeneratorVersion); StartNewLine(); generatedCode.AppendFormat(@"[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"[<System.SerializableAttribute()>]"); StartNewLine(); var grainName = grainInterfaceData.Type.Namespace + "." + TypeUtils.GetParameterizedTemplateName(grainInterfaceData.Type); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.GrainStateAttribute(""{0}"")>]", grainName); StartNewLine(); generatedCode.AppendFormat(@"type {0} {1}", typeAccess, stateClassBaseName); if (genericTypeParams != null && genericTypeParams.Count > 0) { generatedCode.Append('<'); for (int p = 0; p < genericTypeParams.Count; ++p) { if (p > 0) { generatedCode.Append(','); } CodeTypeParameter param = genericTypeParams[p]; generatedCode.Append('\'').Append(param.Name); } generatedCode.Append('>'); } generatedCode.AppendFormat(@"() ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"inherit global.Orleans.CodeGeneration.GrainState(""{0}"")", grainName); StartNewLine(); var declaringTypes = new Dictionary <string, List <KeyValuePair <string, PropertyInfo> > >(); foreach (var pair in asyncProperties) { var dtName = GetGenericTypeName(pair.Value.DeclaringType, referred, nonamespace); if (!declaringTypes.ContainsKey(dtName)) { declaringTypes.Add(dtName, new List <KeyValuePair <string, PropertyInfo> >()); } var lst = declaringTypes[dtName]; lst.Add(pair); } foreach (var declaringType in declaringTypes) { StartNewLine(); generatedCode.AppendFormat(@"interface {0} with", declaringType.Key); IncreaseIndent(); foreach (var pair in declaringType.Value) { var propertyType = pair.Value.PropertyType; bool noCreateNew = propertyType.IsPrimitive || typeof(string).IsAssignableFrom(propertyType) || // Primative types propertyType.IsAbstract || propertyType.IsInterface || propertyType.IsGenericParameter || // No concrete implementation propertyType.GetConstructor(Type.EmptyTypes) == null; // No default constructor var initExpr = noCreateNew ? string.Format("Unchecked.defaultof<{0}>", GetGenericTypeName(propertyType, referred, nonamespace)) : string.Format("{0}()", GetGenericTypeName(propertyType, referred, nonamespace)); StartNewLine(); generatedCode.AppendFormat(@"override val {0} = {1} with get,set", pair.Key, initExpr); } DecreaseIndent(); } GenerateSetAll(asyncProperties, referred); GenerateAsDictionary(asyncProperties, referred); GenerateToString(stateClassName, asyncProperties, referred); // Generate the serialization members. StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.CopierMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Copier(original:obj) : obj ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"input.DeepCopy() :> obj"); DecreaseIndent(); StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.SerializerMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Serializer(original:obj, stream:global.Orleans.Serialization.BinaryTokenStreamWriter, expected:System.Type) : unit ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let input = original :?> {0}", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"input.SerializeTo(stream)"); DecreaseIndent(); StartNewLine(); StartNewLine(); generatedCode.AppendFormat(@"[<global.Orleans.CodeGeneration.DeserializerMethodAttribute()>]"); StartNewLine(); generatedCode.AppendFormat(@"static member public _Deserializer(expected:System.Type, stream:global.Orleans.Serialization.BinaryTokenStreamReader) : obj ="); IncreaseIndent(); StartNewLine(); generatedCode.AppendFormat(@"let result = {0}()", stateClassBaseName); StartNewLine(); generatedCode.AppendFormat(@"result.DeserializeFrom(stream)"); StartNewLine(); generatedCode.AppendFormat(@"result :> obj"); DecreaseIndent(); DecreaseIndent(); return(null); }