using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Threading; namespace CC_Functions.Core { /// /// Extension methods for various types /// public static class GenericExtensions { /// /// Gets an element from the dictionary or adds the default /// /// The dictionary to get from /// The key to check /// The default value to place /// The key type /// The value type /// The element at the key public static TValue Get(this IDictionary dict, TKey key, TValue def = default) { if (!dict.ContainsKey(key)) dict[key] = def; return dict[key]; } /// /// Sets an element and returns it /// /// The dictionary to set in /// The key to set at /// The value to place /// The key type /// The value type /// The value that was placed public static TValue Set(this IDictionary dict, TKey key, TValue val = default) { dict[key] = val; return dict[key]; } /// /// Tries to cast an object /// /// The object to try to parse /// The parsed object (if successful) or the default (usually null) /// The type to cast to /// Whether the cast was successful public static bool TryCast(this object o, out T parsed) { try { parsed = (T) o; return true; } catch { parsed = default; return false; } } /// /// Runs a function that transforms an object in-line /// /// The object to run on /// The function to run /// The input type /// The output type /// public static TOut SelectO(this TIn self, Func func) => func.Invoke(self); /// /// Runs a function under a condition in-line (equal to if) /// /// The condition to check /// The function to run public static void RunIf(bool condition, Action func) { if (condition) func(); } /// /// Parses a string to a value of an enum /// /// The string to parse /// The enum type (MUST be an enum) /// The element public static TEnum ParseToEnum(string value) => (TEnum) Enum.Parse(typeof(TEnum), Enum.GetNames(typeof(TEnum)).First(s => s.ToLower() == value.ToLower())); /// /// Parses a string to a nullable bool (defaults to null if parse fails) /// /// The st string to parse /// The output nullable bool public static bool? ParseBool(string value) => bool.TryParse(value, out bool tmp) ? (bool?) tmp : null; /// /// AND operation for nullable bools (uses True) /// /// First bool to check /// Second bool to check /// The operation result public static bool And(this bool? left, bool? right) => left.True() && right.True(); /// /// OR operation for nullable bools (uses True) /// /// First bool to check /// Second bool to check /// The operation result public static bool Or(this bool? left, bool? right) => left.True() || right.True(); /// /// XOR operation for nullable bools (uses True) /// /// First bool to check /// Second bool to check /// The operation result public static bool Xor(this bool? left, bool? right) => left.Or(right) && !left.And(right); /// /// Whether the nullable bool is true (null->false) /// /// Value to check /// Whether it is true public static bool True(this bool? self) => self == true; /// /// Whether the nullable bool is false (null->false) /// /// Value to check /// Whether it is false public static bool False(this bool? self) => self == false; /// /// Whether the nullable bool is null /// /// Value to check /// Whether it is null public static bool Null(this bool? self) => self == null; /// /// Removes an element from a dictionary by its index (not key) /// /// The dictionary to remove from /// The index of the value /// The key type /// The value type public static void RemoveAt(this Dictionary dict, int index) => dict.Remove(dict.Keys.ToArray()[index]); /// /// "Unshorten" (follow) an URL /// /// The URL to unshorten /// The unshortened URL public static Uri Unshorten(this Uri self) { HttpWebRequest req = (HttpWebRequest) WebRequest.Create(self); req.AllowAutoRedirect = true; req.MaximumAutomaticRedirections = 100; WebResponse resp = req.GetResponse(); return resp.ResponseUri; } /// /// Rounds a RectangleF to a Rectangle instead of flooring /// /// The RectangleF to round /// The rounded Rectangle public static Rectangle Round(this RectangleF self) => Rectangle.Round(self); /// /// Ceilings a RectangleF to a Rectangle instead of flooring /// /// The RectangleF to ceil (?) /// The ceiled (?) Rectangle public static Rectangle Ceiling(this RectangleF self) => Rectangle.Ceiling(self); /// /// Pings an URL to check for availability /// /// The URL to check /// Whether the service is online public static bool Ping(this Uri self) { try { HttpWebRequest request = (HttpWebRequest) WebRequest.Create(self); request.Timeout = 3000; request.AllowAutoRedirect = true; using WebResponse response = request.GetResponse(); return true; } catch { return false; } } /// /// Gets the size of a dictionary /// /// The dictionary to check /// The size of the dictionary public static long GetSize(this DirectoryInfo directory) => IO.GetDirectorySize(directory.FullName); /// /// Adds a directory to an archive recursively /// /// The archive to add to /// The directory to add /// The name of the directory in-archive /// Extensions for files to ignore /// Paths to exclude from adding /// The new entry public static ZipArchiveEntry AddDirectory(this ZipArchive archive, string folderPath, string entryName, string[] ignoredExtensions, string[] ignoredPaths) { entryName = entryName.TrimEnd('/'); ZipArchiveEntry result = archive.CreateEntry($"{entryName}/"); string[] files = Directory.GetFiles(folderPath); foreach (string t in files) if (!ignoredExtensions.Contains(Path.GetExtension(t)) && !ignoredPaths.Any(s => IO.CheckPathEqual(s, t))) archive.CreateEntryFromFile(t, $"{entryName}/{Path.GetFileName(t)}"); string[] dirs = Directory.GetDirectories(folderPath); foreach (string t in dirs) if (!ignoredPaths.Any(s => IO.CheckPathEqual(s, t))) archive.AddDirectory(t, $"{entryName}/{Path.GetFileName(t)}", ignoredExtensions, ignoredPaths); return result; } /// /// Sets the threads cultureInfo properties to InvariantCulture. For testing /// /// The thread to modify public static void ForceInvariantCulture(this Thread thread) { thread.CurrentCulture = CultureInfo.InvariantCulture; thread.CurrentUICulture = CultureInfo.InvariantCulture; } } }