Esempio n. 1
0
        protected override void GenerateEnumValue(IndentingTextWriter w, ComponentCatalog.LoadableClassInfo info)
        {
            var userName = info != null ? info.UserName : "******";
            var name     = info != null ? info.LoadNames[0] : "None";

            w.WriteLine("[ItemInfo(FriendlyName = \"{0}\", DisplayValue = \"{1}\")]", userName,
                        userName);
            w.Write("{0}", name);
        }
Esempio n. 2
0
        protected virtual void GenerateClassName(IndentingTextWriter w, string prefix, ComponentCatalog.LoadableClassInfo component)
        {
            w.WriteLine();
            var className = prefix + component.LoadNames[0];

            w.WriteLine("/// <summary>Module: {0}</summary>", className);
            w.WriteLine("public partial class {0}", className);
            w.WriteLine("{");
        }
Esempio n. 3
0
        protected void GenerateSummaryComment(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            GenerateParameterComment(w, arg.LongName + argSuffix, arg.HelpText);
        }
Esempio n. 4
0
        private void IndentBlockHelper(TextWriter output, HelperOptions options, dynamic context, object[] arguments)
        {
            var indent = int.Parse(arguments.Single().ToString());

            using (var writer = new IndentingTextWriter(output, new string(' ', indent)))
            {
                options.Template(writer, context);
            }
        }
        private string Render(CodeTypeReference ctr)
        {
            var sw  = new StringWriter();
            var ind = new IndentingTextWriter(sw);
            var w   = new CSharpExpressionWriter(ind);

            w.VisitTypeReference(ctr);
            return(sw.ToString());
        }
        protected override void GenerateClassName(IndentingTextWriter w, string prefix, ComponentCatalog.LoadableClassInfo component)
        {
            w.WriteLine();
            var className = prefix + component.LoadNames[0];

            w.WriteLine("/// <summary>Module: {0}</summary>", className);
            w.WriteLine("public static class {0}EntryPoint", className);
            w.WriteLine("{");
        }
 protected override void GenerateUsings(IndentingTextWriter w)
 {
     w.WriteLine("using System;");
     w.WriteLine("using System.Linq;");
     w.WriteLine("using Microsoft.ML.Runtime;");
     w.WriteLine("using Microsoft.ML.Runtime.CommandLine;");
     w.WriteLine("using Microsoft.ML.Runtime.Data;");
     w.WriteLine("using Microsoft.ML.Runtime.Internal.Internallearn;");
 }
Esempio n. 8
0
 protected override void GenerateContent(IndentingTextWriter writer, string prefix, ComponentCatalog.LoadableClassInfo component, string moduleId)
 {
     GenerateSummaryComment(writer, component);
     GenerateReturnComment(writer);
     GenerateModuleAttribute(writer, prefix, component, moduleId);
     GenerateOutputPort(writer);
     GenerateModuleType(writer, component);
     GenerateMethodSignature(writer, prefix, component);
     GenerateImplCall(writer, prefix, component);
 }
Esempio n. 9
0
        protected void GenerateEnums(IndentingTextWriter w, ComponentCatalog.LoadableClassInfo component)
        {
            var argumentInfo = CmdParser.GetArgInfo(component.ArgType, component.CreateArguments());
            var seen         = new HashSet <Tuple <Type, Type> >();

            foreach (var arg in argumentInfo.Args)
            {
                GenerateEnums(w, arg, seen);
            }
        }
        public static void GenerateLoaderAddInputMethod(IndentingTextWriter writer, string className)
        {
            //Constructor.
            writer.WriteLine("[JsonIgnore]");
            writer.WriteLine("private string _inputFilePath = null;");
            writer.WriteLine($"public {className}(string filePath)");
            writer.WriteLine("{");
            writer.Indent();
            writer.WriteLine("_inputFilePath = filePath;");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine("");

            //SetInput.
            writer.WriteLine($"public void SetInput(IHostEnvironment env, Experiment experiment)");
            writer.WriteLine("{");
            writer.Indent();
            writer.WriteLine("IFileHandle inputFile = new SimpleFileHandle(env, _inputFilePath, false, false);");
            writer.WriteLine("experiment.SetInput(InputFile, inputFile);");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine("");

            //GetInputData
            writer.WriteLine("public Var<IDataView> GetInputData() => null;");
            writer.WriteLine("");

            //Apply.
            writer.WriteLine($"public ILearningPipelineStep ApplyStep(ILearningPipelineStep previousStep, Experiment experiment)");
            writer.WriteLine("{");
            writer.Indent();
            writer.WriteLine("Contracts.Assert(previousStep == null);");
            writer.WriteLine("");
            writer.WriteLine($"return new {className}PipelineStep(experiment.Add(this));");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine("");

            //Pipelinestep class.
            writer.WriteLine($"private class {className}PipelineStep : ILearningPipelineDataStep");
            writer.WriteLine("{");
            writer.Indent();
            writer.WriteLine($"public {className}PipelineStep (Output output)");
            writer.WriteLine("{");
            writer.Indent();
            writer.WriteLine("Data = output.Data;");
            writer.WriteLine("Model = null;");
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
            writer.WriteLine("public Var<IDataView> Data { get; }");
            writer.WriteLine("public Var<ITransformModel> Model { get; }");
            writer.Outdent();
            writer.WriteLine("}");
        }
        private void GenerateMethodSignature(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string parent, string parentType, string parentValue, string argSuffix)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            if (arg.IsSubComponentItemType)
            {
                // We need to create a tree with all the subcomponents, unless the subcomponent is a Trainer.
                Contracts.Assert(arg.ItemType.GetGenericTypeDefinition() == typeof(SubComponent <,>));
                var types    = arg.ItemType.GetGenericArguments();
                var baseType = types[0];
                var sigType  = types[1];
                if (sigType == typeof(SignatureDataLoader))
                {
                    return;
                }
                if (IsTrainer(sigType))
                {
                    return;
                }
                var typeName = EnumName(arg, sigType);
                GenerateParameterAttribute(w, arg.LongName, arg.DefaultValue != null ? typeName + "." + arg.DefaultValue : null, arg.HelpText, parent, parentType, parentValue);
                GenerateParameter(w, typeName, arg.LongName + argSuffix);
                var infos = ComponentCatalog.GetAllDerivedClasses(baseType, sigType);
                foreach (var info in infos)
                {
                    var args = info.CreateArguments();
                    if (args == null)
                    {
                        continue;
                    }
                    var argInfo = CmdParser.GetArgInfo(args.GetType(), args);
                    foreach (var a in argInfo.Args)
                    {
                        GenerateMethodSignature(w, a, arg.LongName, typeName, info.LoadNames[0], argSuffix + info.LoadNames[0]);
                    }
                }
            }
            else
            {
                if (IsColumnType(arg))
                {
                    GenerateParameterAttribute(w, arg.LongName, null, arg.HelpText, parent, parentType, parentValue);
                    GenerateParameter(w, "string", arg.LongName + argSuffix);
                }
                else
                {
                    GenerateParameterAttribute(w, arg.LongName, Stringify(arg.DefaultValue), arg.HelpText, parent, parentType, parentValue);
                    GenerateParameter(w, GetCSharpTypeName(arg.ItemType), arg.LongName + argSuffix);
                }
            }
        }
Esempio n. 12
0
 protected override void GenerateContent(IndentingTextWriter writer, string prefix, ComponentCatalog.LoadableClassInfo component, bool generateEnums, string moduleId)
 {
     GenerateImplFields(writer, component, (w, a) => GenerateFieldsOrProperties(w, a, "", GenerateField));
     if (generateEnums)
     {
         GenerateEnums(writer, component);
     }
     GenerateImplFields(writer, component, (w, a) => GenerateFieldsOrProperties(w, a, "", GenerateProperty));
     GenerateMethodSignature(writer, prefix, component);
     GenerateImplBody(writer, component);
 }
        protected void GenerateImplFields(IndentingTextWriter w, ComponentCatalog.LoadableClassInfo component,
                                          Action <IndentingTextWriter, CmdParser.ArgInfo.Arg> fieldGenerator)
        {
            var argumentInfo = CmdParser.GetArgInfo(component.ArgType, component.CreateArguments());
            var arguments    = argumentInfo.Args.Where(a => !a.IsHidden).ToArray();

            foreach (var arg in arguments)
            {
                fieldGenerator(w, arg);
            }
        }
Esempio n. 14
0
 protected override void GenerateUsings(IndentingTextWriter w)
 {
     w.WriteLine("using System;");
     w.WriteLine("using System.Diagnostics.CodeAnalysis;");
     w.WriteLine("using System.Linq;");
     w.WriteLine("using Microsoft.Analytics.MachineLearning;");
     w.WriteLine("using Microsoft.Analytics.Modules;");
     w.WriteLine("using Microsoft.ML.Runtime;");
     w.WriteLine("using Microsoft.ML.Runtime.CommandLine;");
     w.WriteLine("using Microsoft.ML.Runtime.Data;");
     w.WriteLine("using Microsoft.ML.Runtime.Internal.Internallearn;");
 }
Esempio n. 15
0
        private void GenerateInputOutput(IndentingTextWriter writer, ModuleCatalog.EntryPointInfo entryPointInfo, ModuleCatalog catalog)
        {
            var classAndMethod = CSharpGeneratorUtils.GetEntryPointMetadata(entryPointInfo);

            writer.WriteLine($"namespace {classAndMethod.Namespace}");
            writer.WriteLine("{");
            writer.Indent();
            GenerateInput(writer, entryPointInfo, catalog);
            writer.Outdent();
            writer.WriteLine("}");
            writer.WriteLine();
        }
 public static void GenerateSummary(IndentingTextWriter writer, string summary)
 {
     if (string.IsNullOrEmpty(summary))
     {
         return;
     }
     writer.WriteLine("/// <summary>");
     foreach (var line in summary.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
     {
         writer.WriteLine($"/// {line}");
     }
     writer.WriteLine("/// </summary>");
 }
Esempio n. 17
0
        /// <summary>
        /// Generates private fields and public properties for all the fields in the arguments.
        /// Recursively generate fields and properties for subcomponents.
        /// </summary>
        protected void GenerateFieldsOrProperties(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix,
                                                  Action <IndentingTextWriter, string, string, string, bool, string> oneFieldGenerator)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            if (arg.IsSubComponentItemType)
            {
                Contracts.Assert(arg.ItemType.GetGenericTypeDefinition() == typeof(SubComponent <,>));
                var types    = arg.ItemType.GetGenericArguments();
                var baseType = types[0];
                var sigType  = types[1];
                if (sigType == typeof(SignatureDataLoader))
                {
                    return;
                }
                if (IsTrainer(sigType))
                {
                    oneFieldGenerator(w, "Tuple<string, string>", arg.LongName + argSuffix, "", false, arg.HelpText);
                    return;
                }
                var    typeName = EnumName(arg, sigType);
                string defVal   = arg.DefaultValue != null?string.Format(" = {0}.{1}", typeName, arg.DefaultValue) : "";

                oneFieldGenerator(w, typeName, arg.LongName + argSuffix, defVal, arg.ItemType == typeof(bool),
                                  arg.HelpText);
                var infos = ComponentCatalog.GetAllDerivedClasses(baseType, sigType);
                foreach (var info in infos)
                {
                    var args = info.CreateArguments();
                    if (args == null)
                    {
                        continue;
                    }
                    var argInfo = CmdParser.GetArgInfo(args.GetType(), args);
                    foreach (var a in argInfo.Args)
                    {
                        GenerateFieldsOrProperties(w, a, argSuffix + info.LoadNames[0], oneFieldGenerator);
                    }
                }
            }
            else
            {
                object val      = Stringify(arg.DefaultValue);
                string defVal   = val == null ? "" : string.Format(" = {0}", val);
                var    typeName = IsColumnType(arg) ? "string[]" : IsStringColumnType(arg) ? GetCSharpTypeName(arg.Field.FieldType) : GetCSharpTypeName(arg.ItemType);
                oneFieldGenerator(w, typeName, arg.LongName + argSuffix, defVal, arg.ItemType == typeof(bool), arg.HelpText);
            }
        }
 private void GenerateParameterAttribute(IndentingTextWriter w, string displayName, object defaultValue, string description,
                                         string parent = null, string parentType = null, string parentValue = null)
 {
     w.WriteLine("[Help(Display = @\"{0}\", ToolTip = \"{1}\")]", PrettyPrintDisplayName(displayName), description);
     if (parent != null)
     {
         w.WriteLine("[Relevancy(Key = \"{0}\", Values = new object[] {{ {1}.{2} }})]", parent, parentType, parentValue);
     }
     if (defaultValue != null)
     {
         w.WriteLine("[Domain(DefaultValue = {0})]", defaultValue);
     }
     w.WriteLine("[ModuleParameter]");
 }
Esempio n. 19
0
        protected void GenerateImplCall(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            if (arg.IsSubComponentItemType)
            {
                Contracts.Assert(arg.ItemType.GetGenericTypeDefinition() == typeof(SubComponent <,>));
                var types    = arg.ItemType.GetGenericArguments();
                var baseType = types[0];
                var sigType  = types[1];
                if (sigType == typeof(SignatureDataLoader))
                {
                    return;
                }
                if (IsTrainer(sigType))
                {
                    w.WriteLine("builder.{0} = {1};", Capitalize(arg.LongName + argSuffix), arg.LongName + argSuffix);
                    return;
                }
                w.WriteLine("builder.{0} = {1};", Capitalize(arg.LongName + argSuffix), arg.LongName + argSuffix);
                var infos = ComponentCatalog.GetAllDerivedClasses(baseType, sigType);
                foreach (var info in infos)
                {
                    var args = info.CreateArguments();
                    if (args == null)
                    {
                        continue;
                    }
                    var argInfo = CmdParser.GetArgInfo(args.GetType(), args);
                    foreach (var a in argInfo.Args)
                    {
                        GenerateImplCall(w, a, argSuffix + info.LoadNames[0]);
                    }
                }
            }
            else
            {
                if (IsColumnType(arg))
                {
                    w.WriteLine("builder.{0} = {1}.Split('|');", Capitalize(arg.LongName + argSuffix), arg.LongName + argSuffix);
                }
                else
                {
                    w.WriteLine("builder.{0} = {1}{2};", Capitalize(arg.LongName + argSuffix), CastIfNeeded(arg), arg.LongName + argSuffix);
                }
            }
        }
        /// <summary>
        /// Generates private fields and public properties for all the fields in the arguments.
        /// Recursively generate fields and properties for subcomponents.
        /// </summary>
        protected void GenerateFieldsOrProperties(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix,
                                                  Action <IndentingTextWriter, string, string, string, bool, string> oneFieldGenerator)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            object val      = Stringify(arg.DefaultValue);
            string defVal   = val == null ? "" : string.Format(" = {0}", val);
            var    typeName = IsColumnType(arg) ? "string[]" : IsStringColumnType(arg) ? GetCSharpTypeName(arg.Field.FieldType) : GetCSharpTypeName(arg.ItemType);

            oneFieldGenerator(w, typeName, arg.LongName + argSuffix, defVal, arg.ItemType == typeof(bool), arg.HelpText);
        }
        private void ListKinds(IndentingTextWriter writer)
        {
            var sigs = _env.ComponentCatalog.GetAllSignatureTypes()
                       .Select(ComponentCatalog.SignatureToString)
                       .OrderBy(x => x);

            writer.WriteLine("Available component kinds:");
            using (writer.Nest())
            {
                foreach (var sig in sigs)
                {
                    writer.WriteLine(sig);
                }
            }
        }
Esempio n. 22
0
 protected override void GenerateMethodSignature(IndentingTextWriter w, string prefix, ComponentCatalog.LoadableClassInfo component)
 {
     w.Write("public static Tuple<ITrainer> Create{0}{1}(", prefix, component.LoadNames[0]);
     using (w.Nest())
     {
         var argumentInfo = CmdParser.GetArgInfo(component.ArgType, component.CreateArguments());
         var arguments    = argumentInfo.Args.Where(a => !a.IsHidden).ToArray();
         var pre          = "";
         foreach (var arg in arguments)
         {
             GenerateMethodSignature(w, arg, null, null, null, ref pre, "");
         }
         w.WriteLine(")");
     }
 }
 protected override void GenerateMethodSignature(IndentingTextWriter w, string prefix, ComponentCatalog.LoadableClassInfo component)
 {
     w.WriteLine("/// <summary>");
     w.WriteLine("/// Creates a {0}", component.LoadNames[0]);
     w.WriteLine("/// </summary>");
     w.WriteLine("/// <param name=\"env\">The environment</param>");
     w.WriteLine("/// <param name=\"data\">The data set</param>");
     w.WriteLine("/// <returns>The transformed data.</returns>");
     w.WriteLine("public IDataView Create{0}{1}Impl(", prefix, component.LoadNames[0]);
     using (w.Nest())
     {
         w.WriteLine("IHostEnvironment env,");
         w.WriteLine("IDataView data)");
     }
 }
Esempio n. 24
0
        public void Generate(IEnumerable <HelpCommand.Component> infos)
        {
            var catalog = ModuleCatalog.CreateInstance(_host);

            using (var sw = new StreamWriter(_csFilename))
            {
                var writer = IndentingTextWriter.Wrap(sw, "    ");

                // Generate header
                CSharpGeneratorUtils.GenerateHeader(writer);

                foreach (var entryPointInfo in catalog.AllEntryPoints().Where(x => !_excludedSet.Contains(x.Name)).OrderBy(x => x.Name))
                {
                    // Generate method
                    CSharpGeneratorUtils.GenerateMethod(writer, entryPointInfo.Name, _defaultNamespace);
                }

                // Generate footer
                CSharpGeneratorUtils.GenerateFooter(writer);
                CSharpGeneratorUtils.GenerateFooter(writer);

                foreach (var entryPointInfo in catalog.AllEntryPoints().Where(x => !_excludedSet.Contains(x.Name)).OrderBy(x => x.Name))
                {
                    // Generate input and output classes
                    GenerateInputOutput(writer, entryPointInfo, catalog);
                }

                writer.WriteLine("namespace Runtime");
                writer.WriteLine("{");
                writer.Indent();

                foreach (var kind in catalog.GetAllComponentKinds())
                {
                    // Generate kind base class
                    GenerateComponentKind(writer, kind);

                    foreach (var component in catalog.GetAllComponents(kind))
                    {
                        // Generate component
                        GenerateComponent(writer, component, catalog);
                    }
                }

                CSharpGeneratorUtils.GenerateFooter(writer);
                CSharpGeneratorUtils.GenerateFooter(writer);
                writer.WriteLine("#pragma warning restore");
            }
        }
        private void GenerateDictionaryEntry(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            if (IsColumnType(arg))
            {
                GenerateDictionaryEntry(w, "string", arg.LongName + argSuffix);
            }
            else
            {
                GenerateDictionaryEntry(w, GetCSharpTypeName(arg.ItemType), arg.LongName + argSuffix);
            }
        }
Esempio n. 26
0
 private void GenerateComponent(IndentingTextWriter writer, ModuleCatalog.ComponentInfo component, ModuleCatalog catalog)
 {
     GenerateEnums(writer, component.ArgumentType, "Runtime");
     writer.WriteLine();
     GenerateClasses(writer, component.ArgumentType, catalog, "Runtime");
     writer.WriteLine();
     CSharpGeneratorUtils.GenerateSummary(writer, component.Description);
     writer.WriteLine($"public sealed class {CSharpGeneratorUtils.GetComponentName(component)} : {component.Kind}");
     writer.WriteLine("{");
     writer.Indent();
     GenerateInputFields(writer, component.ArgumentType, catalog, "Runtime");
     writer.WriteLine($"internal override string ComponentName => \"{component.Name}\";");
     writer.Outdent();
     writer.WriteLine("}");
     writer.WriteLine();
 }
Esempio n. 27
0
        protected void GenerateImplCall(IndentingTextWriter w, CmdParser.ArgInfo.Arg arg, string argSuffix)
        {
            if (Exclude.Contains(arg.LongName))
            {
                return;
            }

            if (IsColumnType(arg))
            {
                w.WriteLine("builder.{0} = {1}.Split('|');", Capitalize(arg.LongName + argSuffix), arg.LongName + argSuffix);
            }
            else
            {
                w.WriteLine("builder.{0} = {1}{2};", Capitalize(arg.LongName + argSuffix), CastIfNeeded(arg), arg.LongName + argSuffix);
            }
        }
Esempio n. 28
0
        protected void GenerateDataLabParameterAttribute(IndentingTextWriter w, string friendlyName,
                                                         bool isOptional, string displayName, object defaultValue, string description, string parent = null,
                                                         string parentType = null, string parentValue = null)
        {
            string p = parent != null?string.Format(" ParentParameter = \"{0}\",", parent) : "";

            string pv = parentValue != null
                ? string.Format(" ParentParameterValue = new object[] {{ {0}.{1} }},", parentType, parentValue)
                : "";

            string dv = defaultValue != null?string.Format(" DefaultValue = {0},", defaultValue) : "";

            w.WriteLine(
                "[DataLabParameter(FriendlyName = \"{0}\", IsOptional = {1}, DisplayName = \"{2}\",{3}{4}{5} Description = \"{6}\")]",
                friendlyName, isOptional ? "true" : "false", displayName, p, pv, dv, description);
        }
Esempio n. 29
0
 private void GenerateFile(ComponentCatalog.LoadableClassInfo info, string filename, Dictionary <Type, GeneratorBase> mapping, bool generateEnums)
 {
     using (var sw = new StreamWriter(filename))
     {
         var writer = IndentingTextWriter.Wrap(sw, "    ");
         foreach (var kvp in mapping)
         {
             if (info.IsOfType(kvp.Key))
             {
                 kvp.Value.Generate(writer, _modulePrefix, _regenerate, info, generateEnums,
                                    _moduleId ?? Guid.NewGuid().ToString(), _moduleName, _moduleOwner, _moduleVersion, _moduleState,
                                    _moduleType, _moduleDeterminism, _moduleCategory, _exclude, _namespaces);
                 break;
             }
         }
     }
 }
        protected static void GenerateProperty(IndentingTextWriter w, string typeName, string argName, string defVal,
                                               bool isBool, string helpText)
        {
            var help = helpText ?? argName;

            help = help.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;");
            w.WriteLine("/// <summary> Gets or sets {0}{1} </summary>", isBool ? "a value indicating whether " : "", help);
            w.WriteLine("public {0} {1}", typeName, Capitalize(argName));
            w.WriteLine("{");
            using (w.Nest())
            {
                w.WriteLine("get {{ return {0}; }}", argName);
                w.WriteLine("set {{ {0} = value; }}", argName);
            }
            w.WriteLine("}");
            w.WriteLine();
        }
        private static bool WriteUnitOfWork( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( declaration != null );
            Contract.Requires( implementedInterfaces != null );

            if ( implementedInterfaces.Contains( declaration.TypeName ) )
                return false;

            implementedInterfaces.Add( declaration.TypeName );

            writer.WriteLine( "bool {0}.HasPendingChanges", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "get" );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return ChangeTracker.HasChanges();" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterNew( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Set<{0}>().Add( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterRemoved( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Set<{0}>().Remove( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterChanged( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "if ( Entry( item ).State != EntityState.Detached )" );
            writer.Indent();
            writer.WriteLine( "return;" );
            writer.Unindent();
            writer.WriteLine();
            writer.WriteLine( "Set<{0}>().Attach( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "Entry( item ).State = EntityState.Modified;" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.Unregister( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Entry( item ).State = EntityState.Detached;" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.Rollback()", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "foreach ( var entry in ChangeTracker.Entries<{0}>() )", declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "switch ( entry.State )" );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "case EntityState.Modified:" );
            writer.WriteLine( "case EntityState.Deleted:" );
            writer.Indent();
            writer.WriteLine( "entry.CurrentValues.SetValues( entry.OriginalValues );" );
            writer.WriteLine( "entry.State = EntityState.Unchanged;" );
            writer.WriteLine( "break;" );
            writer.Unindent();
            writer.WriteLine( "case EntityState.Added:" );
            writer.Indent();
            writer.WriteLine( "entry.State = EntityState.Detached;" );
            writer.WriteLine( "break;" );
            writer.Unindent();
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "async Task {0}.CommitAsync( CancellationToken cancellationToken )", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "await SaveChangesAsync( cancellationToken ).ConfigureAwait( false );" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );

            return true;
        }
        private static bool WritePropertyChangedImplementation( IndentingTextWriter writer, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( implementedInterfaces != null );

            if ( implementedInterfaces.Contains( INotifyPropertyChanged ) )
                return false;

            implementedInterfaces.Add( INotifyPropertyChanged );

            writer.WriteLine( "public event PropertyChangedEventHandler PropertyChanged;" );
            writer.WriteLine();
            writer.WriteLine( "private void OnPropertyChanged( PropertyChangedEventArgs e ) => PropertyChanged?.Invoke( this, e );" );

            return true;
        }
        private static bool WriteReadOnlyRepository( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( implementedInterfaces != null );

            if ( implementedInterfaces.Contains( declaration.TypeName ) )
                return false;

            implementedInterfaces.Add( declaration.TypeName );

            writer.WriteLine( "async Task<IEnumerable<{1}>> {0}.GetAsync( Func<IQueryable<{1}>, IQueryable<{1}>> queryShaper, CancellationToken cancellationToken )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return await queryShaper( Set<{0}>() ).ToArrayAsync( cancellationToken ).ConfigureAwait( false );", declaration.ArgumentTypeName );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "async Task<TResult> {0}.GetAsync<TResult>( Func<IQueryable<{1}>, TResult> queryShaper, CancellationToken cancellationToken )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return await Task<TResult>.Factory.StartNew( () => queryShaper( Set<{0}>() ), cancellationToken ).ConfigureAwait( false );", declaration.ArgumentTypeName );
            writer.Unindent();
            writer.WriteLine( "}" );

            return true;
        }
        private static void ImplementInterface( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( declaration != null );
            Contract.Requires( implementedInterfaces != null );

            switch ( declaration.Key )
            {
                case IReadOnlyRepository:
                    WriteReadOnlyRepository( writer, declaration, implementedInterfaces );
                    break;
                case IRepository:
                    var inheritedDeclaration = new InterfaceDeclaration( IReadOnlyRepository, declaration );

                    if ( WritePropertyChangedImplementation( writer, implementedInterfaces ) )
                        writer.WriteLine();

                    if ( WriteReadOnlyRepository( writer, inheritedDeclaration, implementedInterfaces ) )
                        writer.WriteLine();

                    WriteRepository( writer, declaration, implementedInterfaces );
                    break;
                case IUnitOfWork:
                    if ( WritePropertyChangedImplementation( writer, implementedInterfaces ) )
                        writer.WriteLine();

                    WriteUnitOfWork( writer, declaration, implementedInterfaces );
                    break;
            }
        }
        private static void WriteEndClass( IndentingTextWriter writer, bool hasNamespace )
        {
            Contract.Requires( writer != null );

            if ( hasNamespace )
            {
                writer.Unindent();
                writer.WriteLine( "}" );
            }

            writer.Unindent();
            writer.Write( "}" );
        }
        private static bool WriteStartClass(
            IndentingTextWriter writer,
            string defaultNamespace,
            IReadOnlyList<UsingDirectiveSyntax> usings,
            ClassDeclarationSyntax @class )
        {
            Contract.Requires( writer != null );
            Contract.Requires( defaultNamespace != null );
            Contract.Requires( usings != null );
            Contract.Requires( @class != null );

            var @namespace = ResolveNamespace( @class, defaultNamespace );
            var hasNamespace = !string.IsNullOrEmpty( @namespace );
            var className = @class.Identifier.Text;

            if ( hasNamespace )
            {
                writer.WriteLine( "namespace {0}", @namespace );
                writer.WriteLine( "{" );
                writer.Indent();
            }

            WriteUsings( writer, usings );
            writer.WriteLine();
            writer.WriteLine( "/// <content>" );
            writer.WriteLine( "/// Provides auto-generated interfaces for the <see cref=\"{0}\" /> class. To add addition interfaces,", className );
            writer.WriteLine( "/// implement the interface in the main source file." );
            writer.WriteLine( "/// <seealso cref=\"IReadOnlyRepository{T}\" />" );
            writer.WriteLine( "/// <seealso cref=\"IRepository{T}\" />" );
            writer.WriteLine( "/// <seealso cref=\"IUnitOfWork{T}\" />." );
            writer.WriteLine( "/// <content>" );
            writer.WriteLine( "[GeneratedCode( \"More Framework\", \"1.0\" )]" );
            writer.WriteLine( "{0}partial class {1}", ResolveScopeModifier( @class ), className );
            writer.WriteLine( "{" );
            writer.Indent();

            return hasNamespace;
        }
        private static void WriteUsings( IndentingTextWriter writer, IReadOnlyList<UsingDirectiveSyntax> declaredUsings )
        {
            Contract.Requires( writer != null );
            Contract.Requires( declaredUsings != null );

            var usings = new SortedSet<UsingDirectiveSyntax>( UsingDirectiveComparer.Instance );

            // merge sorted, distinct list of required and declared usings
            usings.AddRange( RequiredUsings );
            usings.AddRange( declaredUsings );

            // write out required usings
            foreach ( var @using in usings )
                writer.WriteLine( @using );
        }
        private static void ImplementInterfaces(
            CodeGeneratorContext context,
            IReadOnlyList<UsingDirectiveSyntax> usings,
            IReadOnlyList<InterfaceDeclaration> declarations,
            TextWriter writer )
        {
            Contract.Requires( context != null );
            Contract.Requires( declarations != null );
            Contract.Requires( writer != null );

            var iterator = declarations.GetEnumerator();

            if ( !iterator.MoveNext() )
                return;

            var indentingWriter = new IndentingTextWriter( writer );
            var implementedInterfaces = new HashSet<string>();
            var hasNamespace = WriteStartClass( indentingWriter, context.DefaultNamespace, usings, iterator.Current.DefiningClass );

            ImplementInterface( indentingWriter, iterator.Current, implementedInterfaces );

            while ( iterator.MoveNext() )
            {
                writer.WriteLine();
                ImplementInterface( indentingWriter, iterator.Current, implementedInterfaces );
            }

            WriteEndClass( indentingWriter, hasNamespace );
        }