using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Chernobyl.Attribution; using Chernobyl.Collections.Generic; using Chernobyl.Reflection; namespace Chernobyl.Extensions { /// /// Extensions and utility methods for and /// related types. /// public static class KeyAttribute { /// /// Retrieves the values of the parameter using the find method provided. /// /// The parameter to locate values for. /// The method used to locate the parameters. /// The method to invoke when the parameters have /// been found. public static void GetValues(this ParameterInfo parameter, Find find, Callback> callback) { find.FindMany(parameter.GetKeys(), callback); } /// /// Retrieves the value of the parameter using the find method provided. /// /// The parameter to locate value for. /// The method used to locate the parameter. /// The method to invoke when the parameters have /// been found. public static void GetValue(this ParameterInfo parameter, Find find, Callback callback) { parameter.GetValues(find, values => { values.Duplicated() .DefaultIfEmpty(values.First) .To(callback.AsAction()); }); } /// /// Retrieves the values of the parameters using the find method provided. /// /// The parameters to locate values for. /// The method used to locate the parameters. /// The method to invoke when the parameters have /// been found. public static void GetValues(this IEnumerable parameters, Find find, Callback> callback) { find.FindMany(parameters, callback); } /// /// Returns the static, void return methods that are attributed with a /// . /// /// The type to look in for the methods. /// The static, void return methods mapped to their keys. public static IEnumerable> GetActions(this Type type) { Func>> selector = method => method.GetCustomAttributes(typeof(IKeyAttribute), true) .Cast() .Select(attr => new KeyValuePair( attr.Key, () => method.Invoke(null, Array.Empty))); // Grab static methods that have no parameters. return type.GetMethods() .Where(method => method.IsStatic && method.GetParameters().IsEmpty() && method.ReturnType == typeof(void)) .SelectMany(selector); } /// /// Returns the static, void return methods that are attributed with a /// . /// /// The to look in for the /// methods. /// The static, void return methods mapped to their keys. public static IEnumerable> GetActions(this Assembly assembly) { return assembly.GetTypes().SelectMany(type => type.GetActions()); } /// /// Retrieves methods that provide the callback with the return values of /// any static, parameterless methods whose return value has been mapped /// to keys using and returns the value. /// /// The to search for keyed values. /// The items held in methods mapped to the keys. public static IEnumerable>>> GetLocators( this Type type) { IDictionary>> items = new Dictionary>>(); // Grab static methods that have no parameters. var staticMethods = type.GetMethods() .Where(method => method.IsStatic && method.GetParameters().IsEmpty() && method.ReturnType != typeof(void)); // Go through the methods and add them to the dictionary. foreach (var method in staticMethods) { var keyAttribute = (IKeyAttribute)method.ReturnParameter .GetCustomAttribute(typeof(IKeyAttribute), true); if (keyAttribute != null) { var methodInfo = method; items.Add(keyAttribute.Key, callback => callback(methodInfo.Invoke(null, Array.Empty))); } } return items; } /// /// Retrieves methods that provide the callback with the return values of /// any static, parameterless methods whose return value has been mapped /// to keys using and returns the value. /// /// The to search for keyed /// values. /// The items held in methods mapped to the keys. public static IEnumerable>>> GetLocators( this Assembly assembly) { return assembly.GetTypes().SelectMany(type => type.GetLocators()); } /// /// Retrieves methods that, when invoked, invoke any /// static, parameterless methods whose return value has been mapped to /// keys using and returns the value. /// /// The to search for keyed values. /// The items held in methods mapped to the keys. public static IEnumerable>> GetKeyedValues( this Type type) { IDictionary> items = new Dictionary>(); // Grab static methods that have no parameters. var staticMethods = type.GetMethods() .Where(method => method.IsStatic && method.GetParameters().IsEmpty() && method.ReturnType != typeof(void)); // Go through the methods and add them to the dictionary. foreach (var method in staticMethods) { var keyAttribute = (IKeyAttribute)method.ReturnParameter .GetCustomAttribute(typeof(IKeyAttribute), true); if (keyAttribute != null) { var methodInfo = method; items.Add(keyAttribute.Key, () => methodInfo.Invoke(null, Array.Empty)); } } return items; } /// /// Retrieves methods that, when invoked, invoke any /// static, parameterless methods whose return value has been mapped to /// keys using and returns the value. /// /// The to search for keyed /// values. /// The items held in methods mapped to the keys. public static IEnumerable>> GetKeyedValues(this Assembly assembly) { return assembly.GetTypes().SelectMany(type => type.GetKeyedValues()); } /// /// Retrives the keys that have been attributed on the /// using the /// . /// /// The instance attributed with /// . public static IEnumerable GetKeys(this ICustomAttributeProvider provider) { return provider.GetCustomAttributes(true) .Select(attr => attr.Key); } } }