Ejemplo n.º 1
0
        ///<example>
        ///public delegate void MethodWithGenericInputDelegate_T<T>(T input);
        ///private readonly Dictionary<Type[], object> MethodWithGenericInputDelegates_T = new Dictionary<Type[], object>();
        ///public void ImplementMethodWithGenericInput<T>(MethodWithGenericInputDelegate_T<T> implementation)
        ///{
        ///   var key = new Type[] { typeof(T) };
        ///   MethodWithGenericInputDelegates[key] = implementation;
        ///}
        ///public void MethodWithGenericInput<T>(T input)
        ///{
        ///   var key = new Type[] { typeof(T) };
        ///   object implementation;
        ///   if (MethodWithGenericInputDelegates.TryGetValue(key, out implementation))
        ///   {
        ///      ((MethodWithGenericInputDelegate<T>)implementation).Invoke(input);
        ///   }
        ///}
        ///</example>
        private void AppendGenericMethod(MethodInfo info, MemberMetadata method)
        {
            var typesExtension = SanitizeMethodName(method.ParameterTypes);
            var typeofList     = info.GetGenericArguments().Select(type => $"typeof({type.Name})").Aggregate((a, b) => $"{a}, {b}");
            var createKey      = $"var key = new Type[] {{ {typeofList} }};";

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

            writer.Write($"public delegate {method.ReturnType} {delegateName}({method.ParameterTypesAndNames}){method.GenericParameterConstraints};");
            writer.Write($"private readonly Dictionary<Type[], object> {dictionary} = new Dictionary<Type[], object>(new EnumerableEqualityComparer<Type>());");
            writer.Write($"public void Implement{methodName}({delegateName} implementation){method.GenericParameterConstraints}");
            using (writer.Scope) {
                writer.Write(createKey);
                writer.Write($"{dictionary}[key] = implementation;");
            }
            writer.Write($"public {method.ReturnType} {methodName}({method.ParameterTypesAndNames}){method.GenericParameterConstraints}");
            using (writer.Scope) {
                writer.AssignDefaultValuesToOutParameters(info.DeclaringType.Namespace, info.GetParameters());
                writer.Write(createKey);
                writer.Write("object implementation;");
                writer.Write($"if ({dictionary}.TryGetValue(key, out implementation))");
                using (writer.Scope) {
                    writer.Write($"{method.ReturnClause}(({delegateName})implementation).Invoke({method.ParameterNames});");
                }
                if (method.ReturnType != "void")
                {
                    writer.Write("else");
                    using (writer.Scope) {
                        writer.Write($"return default({method.ReturnType});");
                    }
                }
            }

            writer.Write(string.Empty);
        }
Ejemplo n.º 2
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})");
        }