public StubBuilder(CSharpSourceWriter writer) { this.writer = writer; writer.WriteUsings( "System", // Action, Func, Type "System.Collections.Generic", // Dictionary "HavenSoft.AutoImplement.Delegation"); // PropertyImplementation, EventImplementation }
public ClassStubBuilder(CSharpSourceWriter writer) { // the main writer will write the Stub class, which contains the new members. stubWriter = writer; writer.WriteUsings( "System", // Action, Func, Type, IDisposable "System.Collections.Generic", // Dictionary "System.Delegation", // PropertyImplementation, EventImplementation "System.Linq", // ConstructionCompletion uses Linq to get the correct constructor. "System.Runtime.Serialization"); // FormatterServices // the intermediateWriter will write the intermediate class, which contains the override members. intermediateWriter = new CSharpSourceWriter(writer.Indentation); }
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}) {{ }}"); }
/// <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()); }
private void AppendToConstructorFromProperty(PropertyInfo info, MemberMetadata metadata, CSharpSourceWriter deferWriter) { var method = info.GetMethod ?? info.SetMethod; if (method.IsAbstract && !method.IsAssembly && !method.IsFamilyAndAssembly) { if (info.Name == "Item" && info.GetIndexParameters().Length > 0) { // item property maps to two methods, get_Item and set_Item // but since the property is abstract, we have no base implementation // so just like methods, give no default values in the constructor (or defer construction call) } else { stubWriter.Write($"if ({metadata.Name} == null) {metadata.Name} = new PropertyImplementation<{metadata.ReturnType}>();"); deferWriter.Write($"stub.{metadata.Name} = new PropertyImplementation<{metadata.ReturnType}>();"); } } if (method.IsStatic || method.IsPrivate || !method.IsVirtual || method.IsAbstract || method.IsAssembly || method.IsFamilyAndAssembly) { return; } if (info.Name == "Item" && info.GetIndexParameters().Length > 0) { if (info.CanRead) { stubWriter.Write($"if (get_Item == null) get_Item = Base_get_Item;"); } if (CanWrite(info)) { stubWriter.Write($"if (set_Item == null) set_Item = Base_set_Item;"); } if (info.CanRead) { deferWriter.Write($"stub.get_Item = stub.Base_get_Item;"); } if (CanWrite(info)) { deferWriter.Write($"stub.set_Item = stub.Base_set_Item;"); } } else { stubWriter.Write($"if ({metadata.Name} == null)"); using (stubWriter.Scope) { stubWriter.Write($"{metadata.Name} = new PropertyImplementation<{metadata.ReturnType}>();"); if (info.CanRead) { stubWriter.Write($"{metadata.Name}.get = () => Base{metadata.Name};"); } if (CanWrite(info)) { stubWriter.Write($"{metadata.Name}.set = value => Base{metadata.Name} = value;"); } } deferWriter.Write($"stub.{metadata.Name} = new PropertyImplementation<{metadata.ReturnType}>();"); if (info.CanRead) { deferWriter.Write($"stub.{metadata.Name}.get = () => stub.Base{metadata.Name};"); } if (CanWrite(info)) { deferWriter.Write($"stub.{metadata.Name}.set = value => stub.Base{metadata.Name} = value;"); } } }
private void AppendToConstructorFromEvent(EventInfo info, MemberMetadata metadata, CSharpSourceWriter deferWriter) { var addMethod = info.AddMethod; if (addMethod.IsAbstract && !addMethod.IsAssembly && !addMethod.IsFamilyAndAssembly) { stubWriter.Write($"if ({metadata.Name} == null) {metadata.Name} = new EventImplementation<{metadata.HandlerArgsType}>();"); deferWriter.Write($"stub.{metadata.Name} = new EventImplementation<{metadata.HandlerArgsType}>();"); } if (addMethod.IsStatic || addMethod.IsPrivate || !addMethod.IsVirtual || addMethod.IsAbstract || addMethod.IsAssembly || addMethod.IsFamilyAndAssembly) { return; } stubWriter.Write($"if ({metadata.Name} == null)"); using (stubWriter.Scope) { stubWriter.Write($"{metadata.Name} = new EventImplementation<{metadata.HandlerArgsType}>();"); stubWriter.Write($"{metadata.Name}.add = value => Base{metadata.Name}Add(new {metadata.HandlerType}(value));"); stubWriter.Write($"{metadata.Name}.remove = value => Base{metadata.Name}Remove(new {metadata.HandlerType}(value));"); } deferWriter.Write($"stub.{metadata.Name} = new EventImplementation<{metadata.HandlerArgsType}>();"); deferWriter.Write($"stub.{metadata.Name}.add = value => stub.Base{metadata.Name}Add(new {metadata.HandlerType}(value));"); deferWriter.Write($"stub.{metadata.Name}.remove = value => stub.Base{metadata.Name}Remove(new {metadata.HandlerType}(value));"); }
private void AppendToConstructorFromMethod(MethodInfo info, MemberMetadata metadata, CSharpSourceWriter deferWriter) { if (info.IsSpecialName || info.IsStatic || info.IsPrivate || !info.IsVirtual || info.IsAbstract || info.IsAssembly || info.IsFamilyAndAssembly || info.IsGenericMethod) { return; } if (info.IsVirtual && info.Name == "Finalize") { return; // Finalize is special in C#. Use a destructor instead. } var typesExtension = StubBuilder.SanitizeMethodName(metadata.ParameterTypes); var methodsWithMatchingNameButNotSignature = implementedMethods.Where(name => name.Split('(')[0] == metadata.Name && name != $"{metadata.Name}({metadata.ParameterTypes})"); string localImplementationName = methodsWithMatchingNameButNotSignature.Any() ? $"{metadata.Name}_{typesExtension}" : metadata.Name; stubWriter.Write($"if ({localImplementationName} == null) {localImplementationName} = Base{metadata.Name};"); deferWriter.Write($"stub.{localImplementationName} = stub.Base{metadata.Name};"); implementedMethods.Add($"{metadata.Name}({metadata.ParameterTypes})"); }
public DecoratorBuilder(CSharpSourceWriter writer) => this.writer = writer;
public CompositeBuilder(CSharpSourceWriter writer) { this.writer = writer; writer.WriteUsings("System.Linq"); }