예제 #1
0
        /// <summary>
        /// Normally, making a stub method on a baseclass requires two overrides with the same name.
        /// An override method, and a new delegate field with the same name.
        /// But for generic methods, a delegate field with the same name won't work.
        /// Instead, we have a generic delegate, a dictionary for overrides, a caller for the base method, an "ImplementMember" method, and an override for the method.
        /// Since all of these have different names, we can put all the overrides in a single class.
        /// So don't put anything in the helper intermediate class.
        /// </summary>
        private void AppendGenericMethod(MethodInfo info, MemberMetadata metadata)
        {
            var typesExtension = StubBuilder.SanitizeMethodName(metadata.ParameterTypes);
            var typeofList     = info.GetGenericArguments().Select(type => $"typeof({type.Name})").Aggregate((a, b) => $"{a}, {b}");
            var createKey      = $"var key = new Type[] {{ {typeofList} }};";

            var delegateName = $"{metadata.Name}Delegate_{typesExtension}{metadata.GenericParameters}";
            var dictionary   = $"{metadata.Name}Delegates_{typesExtension}";
            var methodName   = $"{metadata.Name}{metadata.GenericParameters}";

            stubWriter.Write($"public delegate {metadata.ReturnType} {delegateName}({metadata.ParameterTypesAndNames}){metadata.GenericParameterConstraints};");

            stubWriter.Write($"private readonly Dictionary<Type[], object> {dictionary} = new Dictionary<Type[], object>(new EnumerableEqualityComparer<Type>());");
            stubWriter.Write($"public void Implement{methodName}({delegateName} implementation){metadata.GenericParameterConstraints}");
            using (stubWriter.Scope) {
                stubWriter.Write(createKey);
                stubWriter.Write($"{dictionary}[key] = implementation;");
            }
            if (!info.IsAbstract)
            {
                stubWriter.Write($"public {metadata.ReturnType} Base{methodName}({metadata.ParameterTypesAndNames}){metadata.GenericParameterConstraints}");
                using (stubWriter.Scope) {
                    stubWriter.Write($"{metadata.ReturnClause}base.{methodName}({metadata.ParameterNames});");
                }
            }
            stubWriter.Write($"{metadata.Access} override {metadata.ReturnType} {methodName}({metadata.ParameterTypesAndNames})");
            using (stubWriter.Scope) {
                stubWriter.AssignDefaultValuesToOutParameters(info.DeclaringType.Namespace, info.GetParameters());
                stubWriter.Write(createKey);
                stubWriter.Write("object implementation;");
                stubWriter.Write($"if ({dictionary}.TryGetValue(key, out implementation))");
                using (stubWriter.Scope) {
                    stubWriter.Write($"{metadata.ReturnClause}(({delegateName})implementation).Invoke({metadata.ParameterNames});");
                }
                stubWriter.Write("else");
                using (stubWriter.Scope) {
                    if (!info.IsAbstract)
                    {
                        stubWriter.Write($"{metadata.ReturnClause}Base{methodName}({metadata.ParameterNames});");
                    }
                    else if (metadata.ReturnType != "void")
                    {
                        stubWriter.Write($"return default({metadata.ReturnType});");
                    }
                }
            }
        }
예제 #2
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})");
        }
예제 #3
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})");
        }