private void CustomRead(DslModeling::SerializationContext serializationContext, DslModeling::ModelElement element, global::System.Xml.XmlReader reader)
        {
            DefaultRead(serializationContext, element, reader);

            ConfigurationSectionModel model = (ConfigurationSectionModel)element;

            // Make sure there's always a Validators instance in the model
            if (model.PropertyValidators == null)
            {
                model.PropertyValidators = new PropertyValidators(model.Store);
            }
        }
コード例 #2
0
        private void GenerateCustomConverters(ConfigurationSectionModel model, CodeCompileUnit generationUnit)
        {
            // Create the namespace block
            CodeNamespace converterNamespace = new CodeNamespace(model.Namespace);

            generationUnit.Namespaces.Add(converterNamespace);

            foreach (CustomTypeConverter converter in model.CustomTypeConverters)
            {
                // Create the converter class
                CodeTypeDeclaration customConverter = new CodeTypeDeclaration(converter.Name);
                converterNamespace.Types.Add(customConverter);
                customConverter.Comments.Add(DocComment("<summary>"));
                if (!string.IsNullOrEmpty(converter.Documentation))
                {
                    customConverter.Comments.Add(DocComment(converter.Documentation));
                }
                else
                {
                    customConverter.Comments.Add(DocComment(string.Format("{0} Custom Converter", converter.Name)));
                }
                customConverter.Comments.Add(DocComment("</summary>"));
                customConverter.Attributes = MemberAttributes.Public;
                customConverter.IsPartial  = true;
                customConverter.IsClass    = true;
                customConverter.Name       = converter.Name;
                customConverter.BaseTypes.Add(GlobalReference(typeof(System.Configuration.ConfigurationConverterBase)));

                CodeTypeReference convertType;
                if (converter.Type is TypeDefinition)
                {
                    convertType = GlobalReference(converter.Type.FullName);
                }
                else
                {
                    convertType = GlobalSelfReference(converter.Type.FullName);
                }

                // Override the ConvertFrom method
                CodeMemberMethod convertFromMethod = new CodeMemberMethod();
                customConverter.Members.Add(convertFromMethod);
                convertFromMethod.Comments.Add(DocComment("<summary>"));
                convertFromMethod.Comments.Add(DocComment(string.Format("Converts from <see cref=\"string\" /> to <see cref=\"{0}\" />.", GetTypeReferenceString(convertType))));
                convertFromMethod.Comments.Add(DocComment("</summary>"));
                convertFromMethod.Comments.Add(DocComment(string.Format("<param name=\"context\">The <see cref=\"{0}\" /> that provides a format context.</param>", GetTypeReferenceString(typeof(System.ComponentModel.ITypeDescriptorContext)))));
                convertFromMethod.Comments.Add(DocComment(string.Format("<param name=\"culture\">The <see cref=\"{0}\" /> to use as the current culture.</param>", GetTypeReferenceString(typeof(System.Globalization.CultureInfo)))));
                convertFromMethod.Comments.Add(DocComment("<param name=\"value\">The <see cref=\"string\" /> to convert from.</param>"));
                convertFromMethod.CustomAttributes.Add(_generatedCodeAttribute);
                convertFromMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                convertFromMethod.ReturnType = _object;
                convertFromMethod.Name       = "ConvertFrom";
                convertFromMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.ComponentModel.ITypeDescriptorContext)), "context"));
                convertFromMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Globalization.CultureInfo)), "culture"));
                convertFromMethod.Parameters.Add(new CodeParameterDeclarationExpression(_object, "value"));
                convertFromMethod.Statements.Add(Comment("IMPORTANT NOTE: The code below does not build by default."));
                convertFromMethod.Statements.Add(Comment("This is a custom type validator that must be implemented"));
                convertFromMethod.Statements.Add(Comment("for it to build. Place the following in a separate file"));
                convertFromMethod.Statements.Add(Comment("and implement the method."));
                convertFromMethod.Statements.Add(Comment(""));

                // Generate a partial class with a ConvertFromStringToX method, then put that
                // generated code into the comments for the ConvertFrom
                // method as an instruction to the user on how to handle the conversion.
                {
                    CodeTypeDeclaration partialElementDeclaration = new CodeTypeDeclaration(customConverter.Name);
                    partialElementDeclaration.Attributes = MemberAttributes.Public;
                    partialElementDeclaration.IsPartial  = true;
                    partialElementDeclaration.IsClass    = true;

                    CodeMemberMethod convertFromMethodImplement = new CodeMemberMethod();
                    partialElementDeclaration.Members.Add(convertFromMethodImplement);
                    convertFromMethodImplement.Attributes = MemberAttributes.Private | MemberAttributes.Final;
                    convertFromMethodImplement.ReturnType = convertType;
                    convertFromMethodImplement.Name       = string.Format("ConvertFromStringTo{0}", converter.Type.Name);
                    convertFromMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.ComponentModel.ITypeDescriptorContext)), "context"));
                    convertFromMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Globalization.CultureInfo)), "culture"));
                    convertFromMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(_string, "value"));

                    // Throw NotImplementedException as per what is normal in generated methods that
                    // are intended to be filled.
                    convertFromMethodImplement.Statements.Add(
                        new CodeThrowExceptionStatement(
                            new CodeObjectCreateExpression(
                                GlobalReference(typeof(NotImplementedException))
                                )
                            )
                        );

                    // Convert to string and place in comments
                    string generatedCode = CodeTypeDeclarationToString(partialElementDeclaration);
                    foreach (string line in generatedCode.Split(new string[] { "\r\n" }, int.MaxValue, StringSplitOptions.None))
                    {
                        convertFromMethod.Statements.Add(Comment(line));
                    }
                    convertFromMethod.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(_this, convertFromMethodImplement.Name, new CodeArgumentReferenceExpression("context"), new CodeArgumentReferenceExpression("culture"), new CodeCastExpression(_string, new CodeArgumentReferenceExpression("value")))));
                }

                // Override the ConvertTo method
                CodeMemberMethod convertToMethod = new CodeMemberMethod();
                customConverter.Members.Add(convertToMethod);
                convertToMethod.Comments.Add(DocComment("<summary>"));
                convertToMethod.Comments.Add(DocComment(string.Format("Converts from <see cref=\"{0}\" /> to <see cref=\"string\" />.", GetTypeReferenceString(convertType))));
                convertToMethod.Comments.Add(DocComment("</summary>"));
                convertToMethod.Comments.Add(DocComment(string.Format("<param name=\"context\">The <see cref=\"{0}\" /> that provides a format context.</param>", GetTypeReferenceString(typeof(System.ComponentModel.ITypeDescriptorContext)))));
                convertToMethod.Comments.Add(DocComment(string.Format("<param name=\"culture\">The <see cref=\"{0}\" /> to use as the current culture.</param>", GetTypeReferenceString(typeof(System.Globalization.CultureInfo)))));
                convertToMethod.Comments.Add(DocComment("<param name=\"value\">The <see cref=\"string\" /> to convert from.</param>"));
                convertToMethod.Comments.Add(DocComment(string.Format("<param name=\"type\">The <see cref=\"{0}\" /> to convert the value parameter to.</param>", GetTypeReferenceString(typeof(System.Type)))));
                convertToMethod.CustomAttributes.Add(_generatedCodeAttribute);
                convertToMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                convertToMethod.ReturnType = _object;
                convertToMethod.Name       = "ConvertTo";
                convertToMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.ComponentModel.ITypeDescriptorContext)), "context"));
                convertToMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Globalization.CultureInfo)), "culture"));
                convertToMethod.Parameters.Add(new CodeParameterDeclarationExpression(_object, "value"));
                convertToMethod.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Type)), "type"));
                convertToMethod.Statements.Add(Comment("IMPORTANT NOTE: The code below does not build by default."));
                convertToMethod.Statements.Add(Comment("This is a custom type validator that must be implemented"));
                convertToMethod.Statements.Add(Comment("for it to build. Place the following in a separate file"));
                convertToMethod.Statements.Add(Comment("and implement the method."));
                convertToMethod.Statements.Add(Comment(""));

                // Generate a partial class with a ConvertToXFromString method, then put that
                // generated code into the comments for the ConvertTo
                // method as an instruction to the user on how to handle the conversion.
                {
                    CodeTypeDeclaration partialElementDeclaration = new CodeTypeDeclaration(customConverter.Name);
                    partialElementDeclaration.Attributes = MemberAttributes.Public;
                    partialElementDeclaration.IsPartial  = true;
                    partialElementDeclaration.IsClass    = true;

                    CodeMemberMethod convertToMethodImplement = new CodeMemberMethod();
                    partialElementDeclaration.Members.Add(convertToMethodImplement);
                    convertToMethodImplement.Attributes = MemberAttributes.Private | MemberAttributes.Final;
                    convertToMethodImplement.ReturnType = _string;
                    convertToMethodImplement.Name       = string.Format("ConvertTo{0}FromString", converter.Type.Name);
                    convertToMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.ComponentModel.ITypeDescriptorContext)), "context"));
                    convertToMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Globalization.CultureInfo)), "culture"));
                    convertToMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(convertType, "value"));
                    convertToMethodImplement.Parameters.Add(new CodeParameterDeclarationExpression(GlobalReference(typeof(System.Type)), "type"));

                    // Suggest a ToString() call
                    convertToMethodImplement.Statements.Add(
                        new CodeMethodReturnStatement(
                            new CodeMethodInvokeExpression(
                                new CodeArgumentReferenceExpression("value"),
                                "ToString"
                                )
                            )
                        );

                    // Convert to string and place in comments
                    string generatedCode = CodeTypeDeclarationToString(partialElementDeclaration);
                    foreach (string line in generatedCode.Split(new string[] { "\r\n" }, int.MaxValue, StringSplitOptions.None))
                    {
                        convertToMethod.Statements.Add(Comment(line));
                    }
                    convertToMethod.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(_this, convertToMethodImplement.Name, new CodeArgumentReferenceExpression("context"), new CodeArgumentReferenceExpression("culture"), new CodeCastExpression(convertType, new CodeArgumentReferenceExpression("value")), new CodeArgumentReferenceExpression("type"))));
                }
            }
        }
コード例 #3
0
        public byte[] GenerateCode(string inputFilePath)
        {
            using (Store store = new Store(typeof(CoreDesignSurfaceDomainModel), typeof(ConfigurationSectionDesignerDomainModel)))
            {
                // Prepare the model
                ConfigurationSectionModel model = PrepareModel(inputFilePath, store);

                // Prepare code generator
                CodeCompileUnit generationUnit = PrepareCodeGenerator();

                // Generate code for the configuration elements
                foreach (BaseConfigurationType type in model.ConfigurationElements)
                {
                    // Ignore any ConfigurationType that is not an instance of
                    // the ConfigurationElement.
                    ConfigurationElement element = type as ConfigurationElement;
                    if (element == null)
                    {
                        continue;
                    }

                    // Create namespace declaration
                    CodeNamespace elementNamespace = new CodeNamespace(element.ActualNamespace);
                    generationUnit.Namespaces.Add(elementNamespace);

                    // Create the element class and set common options
                    CodeTypeDeclaration elementClass = new CodeTypeDeclaration(element.Name);
                    elementNamespace.Types.Add(elementClass);
                    elementClass.Comments.Add(DocComment("<summary>"));
                    elementClass.Comments.Add(DocComment(EscapeStringChars(element.DocumentationText)));
                    elementClass.Comments.Add(DocComment("</summary>"));
                    elementClass.TypeAttributes = (element.AccessModifier == AccessModifiers.Public) ? TypeAttributes.Public : TypeAttributes.NotPublic;
                    if (element.InheritanceModifier == InheritanceModifiers.Abstract)
                    {
                        elementClass.TypeAttributes |= TypeAttributes.Abstract;
                    }
                    else if (element.InheritanceModifier == InheritanceModifiers.Sealed)
                    {
                        elementClass.TypeAttributes |= TypeAttributes.Sealed;
                    }
                    elementClass.IsPartial = true;
                    elementClass.IsClass   = true;

                    if (element.BaseClass != null)
                    {
                        elementClass.BaseTypes.Add(GlobalSelfReference(element.BaseClass.FullName));
                    }

                    // Set element-type specific options
                    if (element is ConfigurationSection)
                    {
                        // Set base type to be ConfigurationSection
                        if (element.BaseClass == null)
                        {
                            elementClass.BaseTypes.Add(GlobalReference(typeof(System.Configuration.ConfigurationSection)));
                        }

                        // Do custom ConfigurationElementCollection code generation
                        GenerateConfigurationSectionCode(element, elementClass);
                    }
                    else if (element is ConfigurationElementCollection)
                    {
                        // Set base type to be ConfigurationElementCollection
                        if (element.BaseClass == null)
                        {
                            elementClass.BaseTypes.Add(GlobalReference(typeof(System.Configuration.ConfigurationElementCollection)));
                        }

                        // Do custom ConfigurationElementCollection code generation
                        GenerateConfigurationElementCollectionCode(element, elementClass);
                    }
                    else if (element is ConfigurationElement)
                    {
                        // Set base type to be ConfigurationElement
                        if (element.BaseClass == null)
                        {
                            elementClass.BaseTypes.Add(GlobalReference(typeof(System.Configuration.ConfigurationElement)));
                        }
                    }

                    // Set IsReadOnly setting
                    CodeMemberMethod isReadOnlyMethod = new CodeMemberMethod();
                    elementClass.Members.Add(isReadOnlyMethod);
                    isReadOnlyMethod.StartDirectives.Add(Region("IsReadOnly override"));
                    isReadOnlyMethod.Comments.Add(DocComment("<summary>"));
                    isReadOnlyMethod.Comments.Add(DocComment("Gets a value indicating whether the element is read-only."));
                    isReadOnlyMethod.Comments.Add(DocComment("</summary>"));
                    isReadOnlyMethod.CustomAttributes.Add(_generatedCodeAttribute);
                    isReadOnlyMethod.Attributes = MemberAttributes.Public | MemberAttributes.Override;
                    isReadOnlyMethod.ReturnType = _bool;
                    isReadOnlyMethod.Name       = "IsReadOnly";
                    isReadOnlyMethod.Statements.Add(
                        new CodeMethodReturnStatement(
                            element.IsReadOnly ? _true : _false
                            )
                        );
                    isReadOnlyMethod.EndDirectives.Add(EndRegion());

                    // Add all the element's properties
                    foreach (ConfigurationProperty property in element.Properties)
                    {
                        GenerateProperty(element, elementClass, property);
                    }

                    if (element.HasCustomChildElements)
                    {
                        GenerateCustomChildElementHandler(elementClass);
                    }
                }

                foreach (TypeDefinition type in model.TypeDefinitions)
                {
                    EnumeratedType enumType = type as EnumeratedType;
                    if (enumType != null && ((enumType.CodeGenOptions & TypeDefinitionCodeGenOptions.TypeDefinition) == TypeDefinitionCodeGenOptions.TypeDefinition))
                    {
                        // Create the namespace block
                        CodeNamespace typeNamespace = new CodeNamespace(enumType.Namespace);
                        generationUnit.Namespaces.Add(typeNamespace);

                        // Create enum
                        CodeTypeDeclaration enumTypeDeclaration = new CodeTypeDeclaration(enumType.Name);
                        typeNamespace.Types.Add(enumTypeDeclaration);
                        enumTypeDeclaration.Comments.Add(DocComment("<summary>"));
                        if (string.IsNullOrEmpty(enumType.Documentation))
                        {
                            // If the enum has no documentation, just make the documentation the name of the enum value
                            enumTypeDeclaration.Comments.Add(DocComment(string.Format("{0}.", enumType.Name)));
                        }
                        else
                        {
                            enumTypeDeclaration.Comments.Add(DocComment(EscapeStringChars(enumType.Documentation)));
                        }
                        enumTypeDeclaration.Comments.Add(DocComment("</summary>"));
                        enumTypeDeclaration.CustomAttributes.Add(_generatedCodeAttribute);
                        if (enumType.IsFlags)
                        {
                            enumTypeDeclaration.CustomAttributes.Add(new CodeAttributeDeclaration(GlobalReference(typeof(FlagsAttribute))));
                        }
                        enumTypeDeclaration.Attributes = MemberAttributes.Public;
                        enumTypeDeclaration.IsEnum     = true;

                        foreach (EnumerationLiteral literal in enumType.Literals)
                        {
                            CodeMemberField enumField = new CodeMemberField();
                            enumTypeDeclaration.Members.Add(enumField);
                            enumField.Comments.Add(DocComment("<summary>"));
                            if (string.IsNullOrEmpty(literal.Documentation))
                            {
                                enumField.Comments.Add(DocComment(string.Format("{0}.", literal.Name)));
                            }
                            else
                            {
                                enumField.Comments.Add(DocComment(EscapeStringChars(literal.Documentation)));
                            }
                            enumField.Comments.Add(DocComment("</summary>"));
                            enumField.Name = literal.Name;
                            if (!string.IsNullOrEmpty(literal.Value))
                            {
                                enumField.InitExpression = new CodeSnippetExpression(literal.Value);
                            }
                        }
                    }
                }

                if (model.PropertyValidators.Validators.Count > 0)
                {
                    GenerateValidators(model, generationUnit);
                }

                if (model.CustomTypeConverters.Count > 0)
                {
                    GenerateCustomConverters(model, generationUnit);
                }

                _generator.GenerateCodeFromCompileUnit(generationUnit, _codeWriter, _options);

                _codeWriter.Flush();
                byte[] output = new byte[_codeStream.Length];
                Array.Copy(_codeStream.GetBuffer(), 0, output, 0, _codeStream.Length);
                return(output);
            }
        }
        // [Note by Max 20140906] TODO this should create a new appdomain to import an assembly and then unloading it.
        // If you load an assembly of the current solution you are not able to build anymore
        // since msbuild is unable to delete the assembly because is currently in use.
        private void ImportExternalEnum()
        {
            OpenFileDialog ofd = new OpenFileDialog()
            {
                DefaultExt = "dll",
                Filter     = "Assemblies (*.dll)|*.dll|All Files (*.*)|*.*"
            };

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                string   file     = ofd.FileName;
                Assembly assembly = Assembly.LoadFrom(file);

                List <Type> enumTypes = new List <Type>();
                foreach (Type type in assembly.GetExportedTypes())
                {
                    if (type.IsEnum)
                    {
                        enumTypes.Add(type);
                    }
                }

                if (enumTypes.Count == 0)
                {
                    MessageBox.Show("The chosen assembly has no public Enums.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                ConfigurationSectionDesignerDiagram diagram = this.SingleDocumentSelection as ConfigurationSectionDesignerDiagram;
                using (Transaction transaction = diagram.Store.TransactionManager.BeginTransaction("Import External Enum"))
                {
                    using (ImportEnumForm importEnumForm = new ImportEnumForm(enumTypes))
                    {
                        if (importEnumForm.ShowDialog() == DialogResult.OK)
                        {
                            ConfigurationSectionModel model = diagram.ModelElement as ConfigurationSectionModel;

                            Type enumType = importEnumForm.SelectedEnum;

                            FlagsAttribute fa = enumType.GetCustomAttributes(false)
                                                .Where(a => a is FlagsAttribute)
                                                .SingleOrDefault() as FlagsAttribute;

                            EnumeratedType enumeratedType = new EnumeratedType(diagram.Store);
                            enumeratedType.CodeGenOptions = TypeDefinitionCodeGenOptions.None;
                            enumeratedType.Name           = enumType.Name;
                            enumeratedType.Namespace      = enumType.Namespace;
                            enumeratedType.IsFlags        = fa != null;

                            FieldInfo[] fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
                            foreach (FieldInfo field in fields)
                            {
                                EnumerationLiteral enumeratedLiteral = new EnumerationLiteral(diagram.Store);
                                enumeratedLiteral.Name = field.Name;

                                enumeratedType.Literals.Add(enumeratedLiteral);
                            }

                            model.TypeDefinitions.Add(enumeratedType);
                            transaction.Commit();
                        }
                        else
                        {
                            transaction.Rollback();
                        }
                    }
                }
            }
        }
コード例 #5
0
        private void GenerateValidators(ConfigurationSectionModel model, CodeCompileUnit generationUnit)
        {
            bool hasCallback = false;

            foreach (PropertyValidator validator in model.PropertyValidators.Validators)
            {
                if (validator is CallbackValidator)
                {
                    hasCallback = true;
                    break;
                }
            }
            if (hasCallback)
            {
                // Create the namespace block
                CodeNamespace callbackValidatorNamespace = new CodeNamespace(model.Namespace);
                generationUnit.Namespaces.Add(callbackValidatorNamespace);

                foreach (PropertyValidator validator in model.PropertyValidators.Validators)
                {
                    CallbackValidator callbackValidator = validator as CallbackValidator;
                    if (callbackValidator == null)
                    {
                        continue;
                    }

                    string callbackClassName  = string.Format("{0}CallbackValidatorClass", callbackValidator.Name);
                    string callbackMethodName = string.Format("{0}Callback", callbackValidator.Callback);
                    string FQ = string.Format("{0}.{1}", model.Namespace, callbackClassName);

                    CodeTypeDeclaration validationCallbackClass = new CodeTypeDeclaration(callbackClassName);
                    callbackValidatorNamespace.Types.Add(validationCallbackClass);
                    validationCallbackClass.Comments.Add(DocComment("<summary>"));
                    validationCallbackClass.Comments.Add(DocComment(string.Format("Class for the {0} callback validator", callbackValidator.Name)));
                    validationCallbackClass.Comments.Add(DocComment("</summary>"));
                    validationCallbackClass.Attributes = MemberAttributes.Public;
                    validationCallbackClass.IsPartial  = true;
                    validationCallbackClass.IsClass    = true;

                    // Generate callback method
                    CodeMemberMethod callbackCallbackMethod = new CodeMemberMethod();
                    callbackCallbackMethod.Comments.Add(DocComment("<summary>"));
                    callbackCallbackMethod.Comments.Add(DocComment(string.Format("Validation callback for the {0} callback validator", callbackValidator.Name)));
                    callbackCallbackMethod.Comments.Add(DocComment("</summary>"));
                    callbackCallbackMethod.Comments.Add(DocComment("<param name=\"value\">The value to validate.</param>"));
                    callbackCallbackMethod.Comments.Add(DocComment(string.Format("<exception cref=\"{0}\">The value was not valid.</exception>", GetTypeReferenceString(typeof(System.ArgumentException)))));
                    callbackCallbackMethod.CustomAttributes.Add(_generatedCodeAttribute);
                    callbackCallbackMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static | MemberAttributes.Final;
                    callbackCallbackMethod.ReturnType = _void;
                    callbackCallbackMethod.Name       = callbackMethodName;
                    callbackCallbackMethod.Parameters.Add(new CodeParameterDeclarationExpression(_object, "value"));
                    callbackCallbackMethod.Statements.Add(Comment("IMPORTANT NOTE: The code below does not build by default."));
                    callbackCallbackMethod.Statements.Add(Comment("You have placed a callback validator on this property."));
                    callbackCallbackMethod.Statements.Add(Comment("Copy the commented code below to a separate file and "));
                    callbackCallbackMethod.Statements.Add(Comment("implement the method."));
                    callbackCallbackMethod.Statements.Add(Comment(""));

                    // Generate a partial class with a callback method, then put that
                    // generated code into the comments for the callback
                    // method as an instruction to the user on how to handle the callback.
                    {
                        CodeTypeDeclaration partialElementDeclaration = new CodeTypeDeclaration(validationCallbackClass.Name);
                        partialElementDeclaration.Attributes = MemberAttributes.Public;
                        partialElementDeclaration.IsPartial  = true;
                        partialElementDeclaration.IsClass    = true;

                        CodeMemberMethod callbackMethod = new CodeMemberMethod();
                        partialElementDeclaration.Members.Add(callbackMethod);
                        callbackMethod.Attributes = callbackCallbackMethod.Attributes;
                        callbackMethod.ReturnType = _void;
                        callbackMethod.Name       = callbackValidator.Callback;
                        callbackMethod.Parameters.Add(new CodeParameterDeclarationExpression(_object, "value"));

                        // Throw NotImplementedException as per what is normal in generated methods that
                        // are intended to be filled.
                        callbackMethod.Statements.Add(
                            new CodeThrowExceptionStatement(
                                new CodeObjectCreateExpression(
                                    GlobalReference(typeof(NotImplementedException))
                                    )
                                )
                            );

                        // Convert to string and place in comments
                        string generatedCode = CodeTypeDeclarationToString(partialElementDeclaration);
                        foreach (string line in generatedCode.Split(new string[] { "\r\n" }, int.MaxValue, StringSplitOptions.None))
                        {
                            callbackCallbackMethod.Statements.Add(Comment(line));
                        }

                        callbackCallbackMethod.Statements.Add(
                            new CodeMethodInvokeExpression(
                                new CodeTypeReferenceExpression(GlobalSelfReference(FQ)),
                                callbackValidator.Callback,
                                new CodeArgumentReferenceExpression("value")
                                )
                            );
                    }

                    validationCallbackClass.Members.Add(callbackCallbackMethod);
                }
            }
        }