private void AppendConstructor(Type type, ConstructorInfo info, MemberMetadata constructorMetadata)
        {
            if (info.IsPrivate || info.IsStatic || info.IsFamilyAndAssembly || info.IsAssembly)
            {
                return;
            }
            var typeName = type.CreateCsName(type.Namespace);

            var(basename, genericInfo) = typeName.ExtractImplementationNameParts("<");
            var intermediateName = $"IntermediateStub{basename}_DoNotUse";
            var stubName         = $"Stub{basename}";

            // for every constructor, make both a constructor and a static "DeferConstruction" method
            var deferWriter = new CSharpSourceWriter(stubWriter.Indentation);

            stubWriter.Write($"public {stubName}({constructorMetadata.ParameterTypesAndNames}) : base({constructorMetadata.ParameterNames})");
            var outParam  = $"out {stubTypeName} uninitializedStub";
            var separator = constructorMetadata.ParameterTypesAndNames.Length > 0 ? ", " : string.Empty;

            deferWriter.Write($"public static IDisposable DeferConstruction({constructorMetadata.ParameterTypesAndNames}{separator}{outParam})");
            using (stubWriter.Scope) {
                using (deferWriter.Scope) {
                    deferWriter.Write($"{stubTypeName} stub;");
                    deferWriter.Write($"var disposable = ConstructionCompletion.CreateObjectWithDeferredConstruction<{stubTypeName}>(out stub{separator}{constructorMetadata.ParameterNames});");
                    foreach (var member in Program.FindAllMembers(type))
                    {
                        var metadata = new MemberMetadata(member, type.Namespace);
                        switch (member.MemberType)
                        {
                        case MemberTypes.Method: AppendToConstructorFromMethod((MethodInfo)member, metadata, deferWriter); break;

                        case MemberTypes.Event: AppendToConstructorFromEvent((EventInfo)member, metadata, deferWriter); break;

                        case MemberTypes.Property: AppendToConstructorFromProperty((PropertyInfo)member, metadata, deferWriter); break;

                        default:
                            // the only other options are Field, Type, NestedType, and Constructor
                            // none of those can be virtual/abstract, so we don't need to put anything in the constructor for them.
                            break;
                        }
                    }
                    deferWriter.Write($"uninitializedStub = stub;");
                    deferWriter.Write($"return disposable;");
                }
            }

            stubWriter.Write(deferWriter.ToString());
            intermediateWriter.Write($"protected {intermediateName}({constructorMetadata.ParameterTypesAndNames}) : base({constructorMetadata.ParameterNames}) {{ }}");
        }
Пример #2
0
        /// <summary>
        /// Creates a Builder of the given generic type to implement the given interface.
        /// Output is placed in the given fileName.
        /// </summary>
        private static void GenerateImplementation <TPatternBuilder>(Type type)
            where TPatternBuilder : IPatternBuilder
        {
            var writer   = new CSharpSourceWriter(numberOfSpacesToIndent: 4);
            var builder  = (TPatternBuilder)Activator.CreateInstance(typeof(TPatternBuilder), writer);
            var fileName = builder.GetDesiredOutputFileName(type);

            Console.WriteLine($"Generating {fileName} ...");

            writer.Write($"// this file was created by AutoImplement");
            writer.Write($"namespace {type.Namespace}");
            using (writer.Scope) {
                writer.Write($"public class {builder.ClassDeclaration(type)}");
                using (writer.Scope) {
                    builder.AppendExtraMembers(type);
                    var allMembers = FindAllMembers(type);
                    foreach (var member in allMembers)
                    {
                        var metadata = new MemberMetadata(member, type.Namespace);
                        switch (member.MemberType)
                        {
                        case MemberTypes.Method: ImplementMethod(member, metadata, builder); break;

                        case MemberTypes.Event: ImplementEvent(member, metadata, builder); break;

                        case MemberTypes.Property: ImplementProperty(member, metadata, builder); break;

                        default:
                            // the only other options are Field, Type, NestedType, and Constructor
                            // for classes, any of these are possible, and all can be ignored.
                            break;
                        }
                    }
                }
                builder.BuildCompleted();
            }

            File.WriteAllText(fileName, writer.ToString());
        }