Ejemplo n.º 1
0
        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));");
        }
Ejemplo n.º 2
0
        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}) {{ }}");
        }
Ejemplo n.º 3
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());
        }
Ejemplo n.º 4
0
        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})");
        }
Ejemplo n.º 5
0
        // <example>
        // public void DoThing(int arg)
        // {
        //    for (int i = 0; i < base.Count; i++)
        //    {
        //       base[i].DoThing(arg);
        //    }
        // }
        // </example>
        /// <remarks>
        /// Composite methods with return types are a bit strange.
        /// If all the methods agree on what to return, then return that.
        /// If any are different, then just return default.
        /// In the case of nullables and bools, this default seems appropriate.
        /// But it can be strange for numeric types.
        ///
        /// For methods that return void, a composite simply forwards the method call down to each thing that it contains.
        /// </remarks>
        public void AppendMethod(MethodInfo info, MemberMetadata method)
        {
            // Use an explicit implementation only if the signature has already been used
            // example: IEnumerable<T>, which extends IEnumerable
            if (!implementedMethods.Any(name => name == $"{method.Name}({method.ParameterTypes})"))
            {
                writer.Write($"public virtual {method.ReturnType} {method.Name}{method.GenericParameters}({method.ParameterTypesAndNames}){method.GenericParameterConstraints}");
            }
            else
            {
                writer.Write($"{method.ReturnType} {method.DeclaringType}.{method.Name}{method.GenericParameters}({method.ParameterTypesAndNames}){method.GenericParameterConstraints}");
            }

            using (writer.Scope) {
                writer.AssignDefaultValuesToOutParameters(info.DeclaringType.Namespace, info.GetParameters());

                if (method.ReturnType == "void")
                {
                    writer.Write("for (int i = 0; i < base.Count; i++)");
                    using (writer.Scope) {
                        writer.Write($"base[i].{method.Name}{method.GenericParameters}({method.ParameterNames});");
                    }
                }
                else
                {
                    writer.Write($"var results = new System.Collections.Generic.List<{method.ReturnType}>();");
                    writer.Write("for (int i = 0; i < base.Count; i++)");
                    using (writer.Scope) {
                        writer.Write($"results.Add(base[i].{method.Name}{method.GenericParameters}({method.ParameterNames}));");
                    }
                    writer.Write("if (results.Count > 0 && results.All(result => result.Equals(results[0])))");
                    using (writer.Scope) {
                        writer.Write("return results[0];");
                    }
                    writer.Write($"return default({method.ReturnType});");
                }
            }

            writer.Write(string.Empty);
            implementedMethods.Add($"{method.Name}({method.ParameterTypes})");
        }
Ejemplo n.º 6
0
        /// <example>
        // public Func<int, int, int> Max { get; set; }
        // int ICalculator.Max(int a, int b)
        // {
        //    if (Max != null)
        //    {
        //       return this.Max(a, b);
        //    }
        //    else
        //    {
        //       return default(int);
        //    }
        // }
        //
        // public Func<double, double, double> Max_double_double { get; set; }
        // double ICalculator.Max(double a, double b)
        // {
        //    if (Max_double_double != null)
        //    {
        //       return this.Max_double_double(a, b);
        //    }
        //    else
        //    {
        //       return default(double);
        //    }
        // }
        /// </example>
        /// <remarks>
        /// Methods in interfaces are replaced with delegate properties.
        /// Assigning one of those delegates a value will change the behavior of that method.
        /// You can call the delegate just like the method.
        /// When the interface method is called, it will call the delegate method if possible.
        /// If there is no delegate, it returns default.
        /// </remarks>
        public void AppendMethod(MethodInfo info, MemberMetadata method)
        {
            if (info.IsGenericMethodDefinition)
            {
                AppendGenericMethod(info, method);
                return;
            }

            var delegateName   = GetStubName(method.ReturnType, method.ParameterTypes);
            var typesExtension = SanitizeMethodName(method.ParameterTypes);

            var    methodsWithMatchingNameButNotSignature = implementedMethods.Where(name => name.Split('(')[0] == method.Name && name != $"{method.Name}({method.ParameterTypes})");
            string localImplementationName = methodsWithMatchingNameButNotSignature.Any() ? $"{method.Name}_{typesExtension}" : method.Name;

            if (info.GetParameters().Any(p => p.ParameterType.IsByRef))
            {
                localImplementationName = $"{method.Name}_{typesExtension}";
                delegateName            = $"{method.Name}Delegate_{typesExtension}";
                writer.Write($"public delegate {method.ReturnType} {delegateName}({method.ParameterTypesAndNames});" + Environment.NewLine);
            }

            // only add a delegation property for the first method with a given signature
            // this is important for IEnumerable<T>.GetEnumerator() and IEnumerable.GetEnumerator() -> same name, same signature
            if (!implementedMethods.Any(name => name == $"{method.Name}({method.ParameterTypes})"))
            {
                writer.Write($"public {delegateName} {localImplementationName} {{ get; set; }}" + Environment.NewLine);
            }

            ImplementInterfaceMethod(info, localImplementationName, method);
            writer.Write(string.Empty);
            implementedMethods.Add($"{method.Name}({method.ParameterTypes})");
        }
Ejemplo n.º 7
0
        public void AppendMethod(MethodInfo info, MemberMetadata metadata)
        {
            if (info.IsStatic || info.IsPrivate || info.IsAssembly || info.IsFamilyAndAssembly)
            {
                return;
            }
            if (!info.IsVirtual && !info.IsAbstract)
            {
                if (metadata.Access == "protected")
                {
                    // the member is protected. Make a public version.
                    stubWriter.Write($"public new {metadata.ReturnType} {metadata.Name}{metadata.GenericParameters}({metadata.ParameterTypesAndNames}){metadata.GenericParameterConstraints}");
                    using (stubWriter.Scope) {
                        stubWriter.Write($"{metadata.ReturnClause}base.{metadata.Name}({metadata.ParameterNames});");
                    }
                }
                return;
            }
            if (info.IsGenericMethodDefinition)
            {
                AppendGenericMethod(info, metadata);
                return;
            }

            var delegateName = GetDelegateName(metadata.ReturnType, metadata.ParameterTypes);

            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;

            if (info.GetParameters().Any(p => p.ParameterType.IsByRef))
            {
                delegateName = $"{metadata.Name}Delegate_{typesExtension}";
                stubWriter.Write($"public delegate {metadata.ReturnType} {delegateName}({metadata.ParameterTypesAndNames});" + Environment.NewLine);
            }

            stubWriter.Write($"public new {delegateName} {localImplementationName};");

            WriteHelperBaseMethod(info, metadata);
            WriteHelperMethod(info, metadata, stubTypeName, localImplementationName);

            implementedMethods.Add($"{metadata.Name}({metadata.ParameterTypes})");
        }
Ejemplo n.º 8
0
        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;");
                }
            }
        }