/// <summary> /// Generates the client proxy code for the given type. /// </summary> public override void Generate() { // ---------------------------------------------------------------- // namespace // ---------------------------------------------------------------- var ns = ClientProxyGenerator.GetOrGenNamespace(Type); // Missing namespace bails out of code-gen -- error has been logged if (ns == null) { return; } // ---------------------------------------------------------------- // public partial class {Type} : (Base) // ---------------------------------------------------------------- ProxyClass = CodeGenUtilities.CreateTypeDeclaration(Type); ProxyClass.IsPartial = true; // makes this a partial type ProxyClass.TypeAttributes = TypeAttributes.Public; // Abstract classes must be preserved as abstract to avoid explicit instantiation on client bool isAbstract = (Type.IsAbstract); if (isAbstract) { ProxyClass.TypeAttributes |= TypeAttributes.Abstract; } // Determine all types derived from this one. // Note this list does not assume the current type is the visible root. That is a separate test. IEnumerable <Type> derivedTypes = GetDerivedTypes(); // If this type doesn't have any derivatives, seal it. Cannot seal abstracts. if (!isAbstract && !derivedTypes.Any()) { ProxyClass.TypeAttributes |= TypeAttributes.Sealed; } // Add all base types including interfaces AddBaseTypes(ns); ns.Types.Add(ProxyClass); AttributeCollection typeAttributes = Type.Attributes(); // Add <summary> xml comment to class string comment = GetSummaryComment(); ProxyClass.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, ClientProxyGenerator.IsCSharp)); // ---------------------------------------------------------------- // Add default ctr // ---------------------------------------------------------------- CodeConstructor constructor = new CodeConstructor(); // Default ctor is public for concrete types but protected for abstracts. // This prevents direct instantiation on client constructor.Attributes = isAbstract ? MemberAttributes.Family : MemberAttributes.Public; // add default ctor doc comments comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Default_Constructor_Summary_Comments, Type.Name); constructor.Comments.AddRange(CodeGenUtilities.GenerateSummaryCodeComment(comment, ClientProxyGenerator.IsCSharp)); // add call to default OnCreated method constructor.Statements.Add(NotificationMethodGen.OnCreatedMethodInvokeExpression); ProxyClass.Members.Add(constructor); // ---------------------------------------------------------------- // [KnownType(...), ...] // ---------------------------------------------------------------- // We need to generate a [KnownType] for all derived entities on the visible root. if (!IsDerivedType) { // Generate a [KnownType] for every derived type. // We specifically exclude [KnownTypes] from the set of attributes we ask // the metadata pipeline to generate below, meaning we take total control // here for which [KnownType] attributes get through the metadata pipeline. // // Note, we sort in alphabetic order to give predictability in baselines and // client readability. For cosmetic reasons, we sort by short or long name // depending on what our utility helpers will actually generated foreach (Type derivedType in derivedTypes.OrderBy(t => ClientProxyGenerator.ClientProxyCodeGenerationOptions.UseFullTypeNames ? t.FullName : t.Name)) { CodeAttributeDeclaration knownTypeAttrib = CodeGenUtilities.CreateAttributeDeclaration(typeof(System.Runtime.Serialization.KnownTypeAttribute), ClientProxyGenerator, ProxyClass); knownTypeAttrib.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(CodeGenUtilities.GetTypeReference(derivedType, ClientProxyGenerator, ProxyClass)))); ProxyClass.CustomAttributes.Add(knownTypeAttrib); } } ValidateTypeAttributes(typeAttributes); // ---------------------------------------------------------------- // [DataContract(Namespace=X, Name=Y)] // ---------------------------------------------------------------- CodeAttributeDeclaration dataContractAttrib = CodeGenUtilities.CreateDataContractAttributeDeclaration(Type, ClientProxyGenerator, ProxyClass); ProxyClass.CustomAttributes.Add(dataContractAttrib); // ---------------------------------------------------------------- // Propagate all type-level Attributes across (except DataContractAttribute since that is handled above) // ----------------------------------------------------------------- CustomAttributeGenerator.GenerateCustomAttributes( ClientProxyGenerator, ProxyClass, ex => string.Format(CultureInfo.CurrentCulture, Resource.ClientCodeGen_Attribute_ThrewException_CodeType, ex.Message, ProxyClass.Name, ex.InnerException.Message), FilterTypeAttributes(typeAttributes), ProxyClass.CustomAttributes, ProxyClass.Comments); // ---------------------------------------------------------------- // gen proxy getter/setter for each property // ---------------------------------------------------------------- GenerateProperties(); // ---------------------------------------------------------------- // gen additional methods/events // ---------------------------------------------------------------- GenerateAdditionalMembers(); // Register created CodeTypeDeclaration with mapping _typeMapping[Type] = ProxyClass; }