diff --git a/Apewer.Windows/Apewer.Windows.csproj b/Apewer.Windows/Apewer.Windows.csproj index 02d7562..bd46bb5 100644 --- a/Apewer.Windows/Apewer.Windows.csproj +++ b/Apewer.Windows/Apewer.Windows.csproj @@ -1,64 +1,66 @@  - + - - CS0108;CS0612 - net461;net40;net20;netcoreapp3.1 - + + CS0108;CS0612 + net461;net40;net20;netcoreapp3.1 + - - - 实现 Windows 程序功能。 - + + + 实现 Windows 程序功能。 + - - - + + + - - - - - - - - - - - + + + + + DRAWING;$(DefineConstants);$(AdditionalConstants) + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/Apewer.Windows/WindowsUtility.cs b/Apewer.Windows/WindowsUtility.cs index e0410b2..270d19d 100644 --- a/Apewer.Windows/WindowsUtility.cs +++ b/Apewer.Windows/WindowsUtility.cs @@ -1039,26 +1039,30 @@ namespace Apewer #if NETFX - /// 创建快捷方式。 - /// 快捷方式路径。 + /// 创建快捷方式,生成 .lnk 文件。 + /// 快捷方式路径,以 .lnk 结尾。 /// 快捷方式图标。可使用 c:\source.exe,0 格式。 /// 快捷方式说明。 /// 源路径。 /// 源参数。 /// 工作目录。 + /// public static void CreateShortcut(string linkPath, string sourcePath, string sourceArgs = null, string linkIcon = null, string linkDescription = null, string directory = null) { // var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // var shortcut = (IWshShortcut)new WshShellClass().CreateShortcut(linkPath); + if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath)); + if (sourcePath.IsEmpty()) throw new ArgumentNullException(nameof(sourcePath)); + var wshShellClass = new IWshRuntimeLibrary.WshShellClass(); var wshObject = wshShellClass.CreateShortcut(linkPath); var wshShortcut = (IWshRuntimeLibrary.IWshShortcut)wshObject; var shortcut = wshShortcut; shortcut.TargetPath = sourcePath ?? ""; - shortcut.Arguments = sourceArgs ?? "arg1"; - shortcut.Description = linkDescription ?? "Invalid Description"; + shortcut.Arguments = sourceArgs ?? ""; + shortcut.Description = linkDescription ?? ""; shortcut.WorkingDirectory = directory ?? ""; - shortcut.IconLocation = linkIcon; + shortcut.IconLocation = linkIcon ?? sourcePath; shortcut.WindowStyle = 1; // shortcut.WorkingDirectory = ""; // shortcut.RelativePath = ""; @@ -1067,6 +1071,36 @@ namespace Apewer #endif + /// 创建 URL 快捷方式,生成 .url 文件。 + /// 快捷方式路径,以 .url 结尾。 + /// URL。 + /// 快捷方式图标。 + /// 快捷方式图标索引。 + /// + public static void CreateUrlShortCut(string linkPath, string url, string iconFilePath = null, int iconIndex = 0) + { + if (linkPath.IsEmpty()) throw new ArgumentNullException(nameof(linkPath)); + if (url.IsEmpty()) throw new ArgumentNullException(nameof(url)); + + var lines = new List(); + lines.Add("[{000214A0-0000-0000-C000-000000000046}]"); + lines.Add("Prop3=19,11"); + lines.Add(""); + lines.Add("[InternetShortcut]"); + lines.Add("IDList="); + lines.Add($"URL={url}"); + if (StorageUtility.FileExists(iconFilePath)) + { + lines.Add($"IconIndex={iconIndex}"); + lines.Add("HotKey=0"); + lines.Add($"IconFile={iconFilePath}"); + } + + var text = lines.Join("\r\n") + "\r\n"; + var bytes = text.Bytes(Encoding.Default); + StorageUtility.WriteFile(linkPath, bytes); + } + #endregion } diff --git a/Apewer/Apewer.csproj b/Apewer/Apewer.csproj index 8f32c8d..77ca79c 100644 --- a/Apewer/Apewer.csproj +++ b/Apewer/Apewer.csproj @@ -1,53 +1,53 @@  - - - - true - 实现通用的实用功能。 - netstandard2.0;netcoreapp3.1;net461;net40;net20 - - - - - NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) - - - - - NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) - - - - - NETFX;NET20;$(DefineConstants);$(AdditionalConstants) - - - - - - - - - NETFX;NET40;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) - - - - - - - - - NETFX;NET461;NET45;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) - - - - - - - - - HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) - + + + + true + 实现通用的实用功能。 + netstandard2.0;netcoreapp3.1;net461;net40;net20 + + + + + NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) + + + + + NETSTD;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) + + + + + NETFX;NET20;DRAWING;$(DefineConstants);$(AdditionalConstants) + + + + + + + + + NETFX;NET40;DRAWING;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) + + + + + + + + + NETFX;NET461;NET45;DRAWING;HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) + + + + + + + + + HAVE_ASYNC;HAVE_BIG_INTEGER;$(DefineConstants);$(AdditionalConstants) + diff --git a/Apewer/BytesUtility.cs b/Apewer/BytesUtility.cs index 20b682c..68371d0 100644 --- a/Apewer/BytesUtility.cs +++ b/Apewer/BytesUtility.cs @@ -271,7 +271,7 @@ namespace Apewer /// 转换字节数组为文本,默认使用 UTF-8 代码页。 public static string ToText(byte[] bytes, Encoding encoding = null) { - if (bytes.Length < 1) return Constant.EmptyString; + if (bytes == null || bytes.Length < 1) return Constant.EmptyString; try { return (encoding ?? Encoding.UTF8).GetString(bytes); } catch { return Constant.EmptyString; } } @@ -464,26 +464,23 @@ namespace Apewer { if (files == null) return null; - var output = new MemoryStream(); - - var input = null as Stream; - var ex = ToZip(files.Keys, output, (name) => + using (var output = new MemoryStream()) { - RuntimeUtility.Dispose(input); - if (name.IsEmpty()) return null; + var ex = ToZip(files.Keys, output, (name) => + { + if (name.IsEmpty()) return null; - var bytes = files[name]; - if (bytes == null || bytes.LongLength < 1L) return null; + var bytes = files[name]; + if (bytes == null || bytes.LongLength < 1L) return null; - input = new MemoryStream(); - Write(input, bytes); - return input; - }, null, true); - RuntimeUtility.Dispose(input); + var input = new MemoryStream(); + Write(input, bytes); + input.Position = 0; + return input; + }, null, true); - var result = output.ToArray(); - RuntimeUtility.Dispose(result); - return result; + return output.ToArray(); + } } /// 解压 ZIP 文件。 @@ -997,7 +994,7 @@ namespace Apewer /// public static byte[] AesDecrypt(byte[] cipher, byte[] key, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) { - return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + return UseAes(cipher, key, null, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV)); } /// 执行 AES 128/192/256 解密。 @@ -1012,7 +1009,7 @@ namespace Apewer /// public static byte[] AesDecrypt(byte[] cipher, byte[] key, byte[] iv, CipherMode cipherMode = CipherMode.ECB, PaddingMode paddingMode = PaddingMode.PKCS7) { - return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateEncryptor(rijndael.Key, rijndael.IV)); + return UseAes(cipher, key, iv, cipherMode, paddingMode, (rijndael) => rijndael.CreateDecryptor(rijndael.Key, rijndael.IV)); } #endregion diff --git a/Apewer/CollectionUtility.cs b/Apewer/CollectionUtility.cs index 51997a9..e809a2e 100644 --- a/Apewer/CollectionUtility.cs +++ b/Apewer/CollectionUtility.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json.Linq; +using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; @@ -126,6 +127,12 @@ namespace Apewer } } + /// 检查当前元素是否存在于集合。 + public static bool In(this T item, IEnumerable collection) => Contains(collection, item); + + /// 检查当前元素是否存在于集合。 + public static bool In(this T item, params T[] collection) => Contains(collection, item); + #endregion #region 类型转换 @@ -474,21 +481,71 @@ namespace Apewer #region 排序 /// 对列表中的元素排序。 - public static List Sort(List list, Func comparison) + /// 返回排序的数组,用于链式写法。 + /// + public static List Sort(this List list, params Comparison[] comparisons) { - if (list == null) return null; - if (comparison == null) return list; - list.Sort(new Comparison(comparison)); + if (list == null) throw new ArgumentNullException(nameof(list)); + if (comparisons == null) throw new ArgumentNullException(nameof(comparisons)); + + var count = comparisons.Length; + if (count < 1) return list; + for (var i = 0; i < count; i++) + { + if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null."); + } + + list.Sort((a, b) => + { + for (var i = 0; i < count; i++) + { + var compare = comparisons[i].Invoke(a, b); + if (compare != 0) return compare; + } + + return Comparer.Default.Compare(a, b); + }); + return list; } /// 对数组排序。 - /// - public static T[] Sort(T[] array, Func comparison) + /// 返回排序的数组,用于链式写法。 + /// + /// + public static T[] Sort(this T[] array) { - if (array == null) return array; - if (comparison == null) return array; - System.Array.Sort(array, new Comparison(comparison)); + System.Array.Sort(array); + return array; + } + + /// 对数组排序。 + /// 返回排序的数组,用于链式写法。 + /// + /// + public static T[] Sort(this T[] array, params Comparison[] comparisons) + { + if (array == null) throw new ArgumentNullException(nameof(array)); + if (comparisons == null) throw new ArgumentNullException(nameof(comparisons)); + + var count = comparisons.Length; + if (count < 1) return array; + for (var i = 0; i < count; i++) + { + if (comparisons[i] == null) throw new ArgumentNullException(nameof(comparisons), $"Comparisons[{i}] is null."); + } + + System.Array.Sort(array, (a, b) => + { + for (var i = 0; i < count; i++) + { + var compare = comparisons[i].Invoke(a, b); + if (compare != 0) return compare; + } + + return Comparer.Default.Compare(a, b); + }); + return array; } @@ -655,7 +712,7 @@ namespace Apewer /// 根据条件筛选,将符合条件的元素组成新数组。 public static T[] FindAll(this IEnumerable collection, Predicate match) { - if (collection == null) new ArgumentNullException(nameof(collection)); + if (collection == null) throw new ArgumentNullException(nameof(collection)); if (match == null) throw new ArgumentNullException(nameof(match)); if (collection is T[] array) @@ -765,7 +822,7 @@ namespace Apewer if (capacity == count) { capacity += 1024; - list.Capacity += capacity; + list.Capacity = capacity; } list.Add(selector.Invoke(item, count)); count += 1; @@ -999,7 +1056,7 @@ namespace Apewer // 生成新数组 var result = new T[array.Length]; for (var i = 0; i < result.Length; i++) result[i] = array[i]; - result[index] = value; + result[offset] = value; return result; } diff --git a/Apewer/DrawingUtility.cs b/Apewer/DrawingUtility.cs new file mode 100644 index 0000000..79d6b99 --- /dev/null +++ b/Apewer/DrawingUtility.cs @@ -0,0 +1,123 @@ +#if DRAWING + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; + +namespace Apewer +{ + + /// 绘图。 + public static class DrawingUtility + { + + /// 优化 Graphics 对象的属性,提升绘图质量。 + public static Graphics Optimize(this Graphics graphics) + { + if (graphics != null) + { + graphics.CompositingMode = CompositingMode.SourceOver; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + } + return graphics; + } + + /// 保存图像为文件。 + /// + public static byte[] Save(this Image image, ImageFormat format) + { + if (image == null) throw new ArgumentNullException(nameof(image)); + if (format == null) throw new ArgumentNullException(nameof(format)); + + using (var memory = new MemoryStream()) + { + image.Save(memory, format); + return memory.ToArray(); + } + } + + /// 保存为 JPEG 文件。 + /// Image 实例。 + /// JPEG 质量,0 为最低质量,100 为最高质量。 + /// + /// + /// + public static byte[] SaveAsJpeg(this Image image, int quality = 100) + { + if (image == null) throw new ArgumentNullException(nameof(image)); + if (quality < 0 || quality > 100) throw new ArgumentOutOfRangeException(nameof(quality)); + + var codec = ImageCodecInfo.GetImageDecoders().Find(x => x.FormatID == ImageFormat.Jpeg.Guid); + if (codec == null) throw new System.Runtime.InteropServices.ExternalException($"系统中不存在 JPEG 编码器。"); + + var parameters = new EncoderParameters(1); + parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); + + using (var memory = new MemoryStream()) + { + image.Save(memory, codec, parameters); + return memory.ToArray(); + } + } + + /// 缩放图像,生成新图像。 + /// 原始图像。 + /// 新图像的大小。 + /// 填充新图像背景色。 + /// + /// + public static Bitmap Scale(this Image image, Size size, Color? backgroundColor = null) => Scale(image, size.Width, size.Height, backgroundColor); + + /// 缩放图像,生成新图像。 + /// 原始图像。 + /// 新图像的宽度。 + /// 新图像的高度。 + /// 填充新图像背景色。 + /// + /// + static Bitmap Scale(this Image image, int width, int height, Color? backgroundColor = null) + { + if (image == null) throw new ArgumentNullException(nameof(image)); + if (width < 1) throw new ArgumentOutOfRangeException(nameof(width)); + if (height < 1) throw new ArgumentOutOfRangeException(nameof(height)); + + // 检查原始图像是否为透明格式 + var rawFormat = image.RawFormat; + var isTransparentFormat = rawFormat.Equals(ImageFormat.Png) || rawFormat.Equals(ImageFormat.Gif); + var pixelFormat = isTransparentFormat ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; + + var bitmap = new Bitmap(width, height, pixelFormat); + try + { + using (var graphic = Graphics.FromImage(bitmap)) + { + graphic.CompositingMode = CompositingMode.SourceOver; + graphic.CompositingQuality = CompositingQuality.HighQuality; + graphic.SmoothingMode = SmoothingMode.AntiAlias; + + // 填充背景色 + if (isTransparentFormat) + { + if (backgroundColor != null && backgroundColor.HasValue) graphic.Clear(backgroundColor.Value); + } + + // 绘制新图像 + graphic.DrawImage(image, 0, 0, width, height); + } + return bitmap; + } + catch + { + bitmap.Dispose(); + throw; + } + } + + } + +} + +#endif diff --git a/Apewer/Logger.cs b/Apewer/Logger.cs index 6ab5467..4964265 100644 --- a/Apewer/Logger.cs +++ b/Apewer/Logger.cs @@ -365,7 +365,7 @@ namespace Apewer if (bytes.Length > 0) { var gzipData = BytesUtility.ToGzip(bytes); - if (gzipData != null || gzipData.Length > 0) + if (gzipData != null && gzipData.Length > 0) { var gzipPath = path + ".gzip"; StorageUtility.WriteFile(gzipPath, gzipData); diff --git a/Apewer/NumberUtility.cs b/Apewer/NumberUtility.cs index 52b6fa2..d6706a9 100644 --- a/Apewer/NumberUtility.cs +++ b/Apewer/NumberUtility.cs @@ -428,7 +428,6 @@ namespace Apewer foreach (var value in values) { up += (value - avg) * (value - avg); - count++; } } diff --git a/Apewer/Source/Execute.cs b/Apewer/Source/Execute.cs index 80df06a..c5cfa78 100644 --- a/Apewer/Source/Execute.cs +++ b/Apewer/Source/Execute.cs @@ -24,7 +24,7 @@ namespace Apewer.Source /// 创建实例。 public Execute(bool success, string message) { - _success = false; + _success = success; _message = message; } diff --git a/Apewer/Source/Query.cs b/Apewer/Source/Query.cs index d1fc953..44e1d7e 100644 --- a/Apewer/Source/Query.cs +++ b/Apewer/Source/Query.cs @@ -22,7 +22,7 @@ namespace Apewer.Source /// 创建实例,默认状态为失败。 public Query(bool success = false, string message = null) { - _success = false; + _success = success; _message = message; } diff --git a/Apewer/Source/SourceUtility.cs b/Apewer/Source/SourceUtility.cs index d5a7834..c0ae115 100644 --- a/Apewer/Source/SourceUtility.cs +++ b/Apewer/Source/SourceUtility.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using System.Reflection; +using System.Runtime.InteropServices.ComTypes; using System.Text; namespace Apewer.Source @@ -598,7 +599,6 @@ namespace Apewer.Source } } - /// 查询。 /// 数据库连接。 /// SQL 语句。 @@ -629,6 +629,353 @@ namespace Apewer.Source } } +#if !NET20 + + /// 执行查询,将结果输出为元组数组。 + /// 元组中的值类型。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, Func getValue) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue == null) throw new ArgumentNullException(nameof(getValue)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var value1 = getValue(query.Value(i, 0)); + tuples[i] = new Tuple(value1); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + tuples[i] = new Tuple(v1, v2); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + tuples[i] = new Tuple(v1, v2, v3); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 获取第四个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3, + Func getValue4) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + var v4 = getValue4(query.Value(i, 3)); + tuples[i] = new Tuple(v1, v2, v3, v4); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 获取第四个值的回调函数。 + /// 获取第五个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3, + Func getValue4, + Func getValue5) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4)); + if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + var v4 = getValue4(query.Value(i, 3)); + var v5 = getValue5(query.Value(i, 4)); + tuples[i] = new Tuple(v1, v2, v3, v4, v5); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 获取第四个值的回调函数。 + /// 获取第五个值的回调函数。 + /// 获取第六个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3, + Func getValue4, + Func getValue5, + Func getValue6) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4)); + if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5)); + if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + var v4 = getValue4(query.Value(i, 3)); + var v5 = getValue5(query.Value(i, 4)); + var v6 = getValue6(query.Value(i, 5)); + tuples[i] = new Tuple(v1, v2, v3, v4, v5, v6); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 获取第四个值的回调函数。 + /// 获取第五个值的回调函数。 + /// 获取第六个值的回调函数。 + /// 获取第七个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3, + Func getValue4, + Func getValue5, + Func getValue6, + Func getValue7) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4)); + if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5)); + if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6)); + if (getValue7 == null) throw new ArgumentNullException(nameof(getValue7)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + var v4 = getValue4(query.Value(i, 3)); + var v5 = getValue5(query.Value(i, 4)); + var v6 = getValue6(query.Value(i, 5)); + var v7 = getValue7(query.Value(i, 6)); + tuples[i] = new Tuple(v1, v2, v3, v4, v5, v6, v7); + } + return tuples; + } + } + + /// 执行查询,将结果输出为元组数组。 + /// 数据库连接。 + /// SQL 语句。 + /// SQL 参数。 + /// 获取第一个值的回调函数。 + /// 获取第二个值的回调函数。 + /// 获取第三个值的回调函数。 + /// 获取第四个值的回调函数。 + /// 获取第五个值的回调函数。 + /// 获取第六个值的回调函数。 + /// 获取第七个值的回调函数。 + /// 获取第八个值的回调函数。 + /// 由元组组成的数组。 + /// + /// + public static Tuple[] Query(this IDbAdo dbClient, string sql, object parameters, + Func getValue1, + Func getValue2, + Func getValue3, + Func getValue4, + Func getValue5, + Func getValue6, + Func getValue7, + Func getValue8) + { + if (dbClient == null) throw new ArgumentNullException(nameof(dbClient)); + if (sql.IsEmpty()) throw new ArgumentNullException(nameof(sql)); + if (getValue1 == null) throw new ArgumentNullException(nameof(getValue1)); + if (getValue2 == null) throw new ArgumentNullException(nameof(getValue2)); + if (getValue3 == null) throw new ArgumentNullException(nameof(getValue3)); + if (getValue4 == null) throw new ArgumentNullException(nameof(getValue4)); + if (getValue5 == null) throw new ArgumentNullException(nameof(getValue5)); + if (getValue6 == null) throw new ArgumentNullException(nameof(getValue6)); + if (getValue7 == null) throw new ArgumentNullException(nameof(getValue7)); + if (getValue8 == null) throw new ArgumentNullException(nameof(getValue8)); + + using (var query = dbClient.Query(sql, parameters)) + { + if (!query.Success) throw new SqlException(query, sql); + + var tuples = new Tuple[query.Rows]; + for (var i = 0; i < query.Rows; i++) + { + var v1 = getValue1(query.Value(i, 0)); + var v2 = getValue2(query.Value(i, 1)); + var v3 = getValue3(query.Value(i, 2)); + var v4 = getValue4(query.Value(i, 3)); + var v5 = getValue5(query.Value(i, 4)); + var v6 = getValue6(query.Value(i, 5)); + var v7 = getValue7(query.Value(i, 6)); + var v8 = getValue8(query.Value(i, 7)); + tuples[i] = new Tuple(v1, v2, v3, v4, v5, v6, v7, v8); + } + return tuples; + } + } + +#endif #endregion @@ -1268,7 +1615,7 @@ namespace Apewer.Source #region Dynamic -#if NET40_OR_GREATER +#if !NET20 /// 转换 ObjectSet 数组为 dynamic 数组。 public static dynamic[] Dynamic(this ObjectSet[] oss) diff --git a/Apewer/Source/SqlException.cs b/Apewer/Source/SqlException.cs index d35d8f0..47679e5 100644 --- a/Apewer/Source/SqlException.cs +++ b/Apewer/Source/SqlException.cs @@ -14,6 +14,7 @@ namespace Apewer.Source string _msg = null; string _sql = null; + object _parameters = null; /// 获取描述当前异常的消息。 public override string Message { get => _msg; } @@ -21,20 +22,25 @@ namespace Apewer.Source /// 获取引发异常的 SQL 语句。 public string Statement { get => _sql; } + /// 获取引发异常的 SQL 参数。 + public object Parameters { get => _parameters; } + /// 初始化 类的新实例。 /// 描述当前异常的消息。 /// 附带 SQL 语句。 - public SqlException(string message, string statement = null) + /// 附带 SQL 参数。 + public SqlException(string message, string statement = null, object parameters = null) { _msg = string.IsNullOrEmpty(message) ? EmptyMessage : message; - _sql = statement; + _parameters = parameters; } /// 初始化 类的新实例。 /// 用于获取消息的查询结果。 /// 附带 SQL 语句。 - public SqlException(IQuery query, string statement = null) + /// 附带 SQL 参数。 + public SqlException(IQuery query, string statement = null, object parameters = null) { if (query == null) { @@ -44,15 +50,17 @@ namespace Apewer.Source } _msg = query.Message; - if (string.IsNullOrEmpty(_msg)) _msg = EmptyMessage; + if (string.IsNullOrEmpty(Message)) _msg = EmptyMessage; _sql = statement; + _parameters = parameters; } /// 初始化 类的新实例。 /// 用于获取消息的执行结果。 /// 附带 SQL 语句。 - public SqlException(IExecute execute, string statement = null) + /// 附带 SQL 参数。 + public SqlException(IExecute execute, string statement = null, object parameters = null) { if (execute == null) { @@ -61,9 +69,10 @@ namespace Apewer.Source } _msg = execute.Message; - if (string.IsNullOrEmpty(_msg)) _msg = EmptyMessage; + if (string.IsNullOrEmpty(Message)) _msg = EmptyMessage; _sql = statement; + _parameters = parameters; } } diff --git a/Apewer/StorageUtility.cs b/Apewer/StorageUtility.cs index 49f5510..e4eb4b6 100644 --- a/Apewer/StorageUtility.cs +++ b/Apewer/StorageUtility.cs @@ -82,7 +82,7 @@ namespace Apewer if (!Directory.Exists(path)) return new DirectoryNotFoundException(); var temp = Environment.GetEnvironmentVariable("TEMP"); - var name = Path.GetDirectoryName(path); + var name = Path.GetFileName(path); var dest = null as string; while (dest == null || Directory.Exists(dest)) diff --git a/Apewer/TextUtility.cs b/Apewer/TextUtility.cs index 4c7b208..33e6cab 100644 --- a/Apewer/TextUtility.cs +++ b/Apewer/TextUtility.cs @@ -137,7 +137,7 @@ namespace Apewer if (cell is string) text = cell as string; else if (cell is Type type) text = type.Name; - else cell.ToString(); + else text = cell.ToString(); if (string.IsNullOrEmpty(text)) continue; if (!first && hasSeparator) sb.Append(separator); @@ -610,7 +610,8 @@ namespace Apewer // foot length = text.IndexOf(foot); - if (length < 1) return text; + if (length == 0) return Empty; + if (length < 0) return text; return text.Substring(0, length); } else diff --git a/Apewer/Web/IApiMiddleware.cs b/Apewer/Web/IApiMiddleware.cs index 7cd5277..78357f0 100644 --- a/Apewer/Web/IApiMiddleware.cs +++ b/Apewer/Web/IApiMiddleware.cs @@ -5,7 +5,8 @@ public interface IApiMiddleware { - /// 调用中间件。 + /// 执行中间件。 + /// 调用 方法可继续处理请求;若不调用则终止请求。 void Invoke(ApiContext context); } diff --git a/Apewer/_Extensions.cs b/Apewer/_Extensions.cs index 7287871..249f9d5 100644 --- a/Apewer/_Extensions.cs +++ b/Apewer/_Extensions.cs @@ -475,7 +475,7 @@ public static class Extensions public static T[] Array(IEnumerable @this, bool excludeNull = false) => CollectionUtility.Array(@this, excludeNull); /// 对列表中的元素排序。 - public static List Sort(this List @this, Func comparison) => CollectionUtility.Sort(@this, comparison); + public static List Sort(this List @this, Comparison comparison) => CollectionUtility.Sort(@this, comparison); /// 对字典中的键排序。 public static Dictionary SortKey(this Dictionary @this, Func comparison) => CollectionUtility.SortKey(@this, comparison);