diff --git a/README.md b/README.md index 6da2b13..8095bfb 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Nuget](https://img.shields.io/nuget/v/SharpHelpers?style=plastic)](https://www.nuget.org/packages/SharpHelpers) +![NuGet Downloads](https://img.shields.io/nuget/dt/SharpHelpers) [![issues - SharpHelpers](https://img.shields.io/github/issues/sharpcode-it/SharpHelpers)](https://github.com/sharpcode-it/SharpHelpers/issues) [![stars - SharpHelpers](https://img.shields.io/github/stars/sharpcode-it/SharpHelpers?style=social)](https://github.com/sharpcode-it/SharpHelpers) diff --git a/SharpHelpers/SharpHelpers.UnitTest/SharpHelpers.UnitTest.csproj b/SharpHelpers/SharpHelpers.UnitTest/SharpHelpers.UnitTest.csproj index 587d005..de71052 100644 --- a/SharpHelpers/SharpHelpers.UnitTest/SharpHelpers.UnitTest.csproj +++ b/SharpHelpers/SharpHelpers.UnitTest/SharpHelpers.UnitTest.csproj @@ -1,15 +1,15 @@  - netcoreapp3.1 + net9.0 false - - - + + + diff --git a/SharpHelpers/SharpHelpers.sln b/SharpHelpers/SharpHelpers.sln index ffa0218..3a836ec 100755 --- a/SharpHelpers/SharpHelpers.sln +++ b/SharpHelpers/SharpHelpers.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.645 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.36105.23 d17.13 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHelpers", "SharpHelpers\SharpHelpers.csproj", "{0B9C8349-C268-46BE-85C7-CBBF125C120B}" EndProject diff --git a/SharpHelpers/SharpHelpers/DataTableHelper.cs b/SharpHelpers/SharpHelpers/DataTableHelper.cs index 6df897a..2a0e80e 100644 --- a/SharpHelpers/SharpHelpers/DataTableHelper.cs +++ b/SharpHelpers/SharpHelpers/DataTableHelper.cs @@ -63,17 +63,21 @@ public static DataTable SetColumnsOrder(this DataTable table, string[] columnNam public static string ToCsv(this DataTable table, string delimiter = ",") { if (table == null) throw new ArgumentNullException(nameof(table)); - - var csv = new List(); - var headers = string.Join(delimiter, table.Columns.Cast().Select(c => c.ColumnName)); - csv.Add(headers); - - foreach (DataRow row in table.Rows) + string Escape(string s) { - var line = string.Join(delimiter, row.ItemArray.Select(field => field?.ToString())); - csv.Add(line); + if (s == null) return ""; + bool needQuotes = s.Contains(delimiter) || s.Contains('"') || s.Contains('\n') || s.Contains('\r'); + if (s.Contains('"')) s = s.Replace("\"", "\"\""); + return needQuotes ? $"\"{s}\"" : s; } - return string.Join(Environment.NewLine, csv); + + var lines = new List(table.Rows.Count + 1) + { + string.Join(delimiter, table.Columns.Cast().Select(c => Escape(c.ColumnName))) + }; + foreach (DataRow row in table.Rows) + lines.Add(string.Join(delimiter, row.ItemArray.Select(v => Escape(v?.ToString())))); + return string.Join(Environment.NewLine, lines); } /// @@ -83,15 +87,22 @@ public static string ToCsv(this DataTable table, string delimiter = ",") /// /// /// - public static void AddColumn(this DataTable table, string columnName, T defaultValue = default) + public static void AddColumn(this DataTable table, string columnName, T defaultValue = default!) { if (table == null) throw new ArgumentNullException(nameof(table)); - - var column = new DataColumn(columnName, typeof(T)) { DefaultValue = defaultValue }; - table.Columns.Add(column); + if (string.IsNullOrWhiteSpace(columnName)) throw new ArgumentException("Empty", nameof(columnName)); + if (table.Columns.Contains(columnName)) + return; + + var t = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); + var col = new DataColumn(columnName, t) + { + DefaultValue = defaultValue! + }; + table.Columns.Add(col); foreach (DataRow row in table.Rows) { - row[columnName] = defaultValue; + row[columnName] = defaultValue!; } } @@ -104,30 +115,50 @@ public static void AddColumn(this DataTable table, string columnName, T defau public static DataTable MergeTables(IEnumerable tables) { if (tables == null) throw new ArgumentNullException(nameof(tables)); + var list = tables.Where(t => t != null).ToList(); + if (list.Count == 0) throw new ArgumentException("No tables."); - var resultTable = tables.First().Clone(); - foreach (var table in tables) + var result = list[0].Clone(); + foreach (var t in list) { - if (!AreSchemasCompatible(resultTable, table)) + if (!AreSchemasCompatible(result, t)) throw new ArgumentException("Tables have incompatible schemas."); - - foreach (DataRow row in table.Rows) + foreach (DataRow r in t.Rows) { - resultTable.ImportRow(row); + result.ImportRow(r); } } - return resultTable; + + return result; } - private static bool AreSchemasCompatible(DataTable table1, DataTable table2) + /// + /// Determines whether two instances have compatible schemas + /// for position-based operations (e.g., cloning and row import). + /// + /// + /// The first table whose schema is used as the reference (column order matters). + /// + /// + /// The second table to compare against . + /// + /// + /// true if both tables have the same number of columns and, at each position, + /// the column name matches (case-insensitive) and the matches; + /// otherwise, false. + /// + /// + /// This check is strictly positional: it does not attempt to realign columns by name. + /// Extended properties, nullability metadata, constraints, and keys are not compared. + /// + private static bool AreSchemasCompatible(DataTable a, DataTable b) { - if (table1.Columns.Count != table2.Columns.Count) return false; - - for (int i = 0; i < table1.Columns.Count; i++) + if (a.Columns.Count != b.Columns.Count) return false; + for (int i = 0; i < a.Columns.Count; i++) { - if (table1.Columns[i].ColumnName != table2.Columns[i].ColumnName || - table1.Columns[i].DataType != table2.Columns[i].DataType) - return false; + var ca = a.Columns[i]; var cb = b.Columns[i]; + if (!ca.ColumnName.Equals(cb.ColumnName, StringComparison.OrdinalIgnoreCase)) return false; + if (ca.DataType != cb.DataType) return false; } return true; } diff --git a/SharpHelpers/SharpHelpers/DictionaryHelper.cs b/SharpHelpers/SharpHelpers/DictionaryHelper.cs index 53b0f1d..b9e9080 100644 --- a/SharpHelpers/SharpHelpers/DictionaryHelper.cs +++ b/SharpHelpers/SharpHelpers/DictionaryHelper.cs @@ -120,6 +120,76 @@ public static string ToReadableString(this Dictionary + /// Returns the value associated with the specified key, or the default value if the key does not exist. + /// + /// The dictionary to query. + /// The key to look for. + /// The value associated with the key, or default if not found. + public static TValue GetValueOrDefault(this IDictionary dictionary, TKey key) + { + return dictionary.TryGetValue(key, out var value) ? value : default; + } + + /// + /// Checks whether all specified keys exist in the dictionary. + /// + /// The dictionary to check. + /// The keys to check for existence. + /// True if all keys exist; otherwise, false. + public static bool ContainsAllKeys(this IDictionary dictionary, IEnumerable keys) + { + return keys.All(k => dictionary.ContainsKey(k)); + } + + /// + /// Tries to get the value associated with the key and cast it to the specified type. + /// + /// The key type. + /// The stored value type. + /// The desired result type. + /// The dictionary to query. + /// The key to retrieve. + /// The casted result if successful; otherwise, default. + /// True if the cast was successful; otherwise, false. + public static bool TryGetValueAs(this IDictionary dictionary, TKey key, out TResult result) + { + result = default; + if (dictionary.TryGetValue(key, out var value) && value is TResult casted) + { + result = casted; + return true; + } + return false; + } + + /// + /// Increments the value associated with the specified key by a given amount. If the key does not exist, it is added with the amount as its value. + /// + /// The dictionary to operate on. + /// The key whose value to increment. + /// The amount to increment by. + public static void IncrementValue(this IDictionary dictionary, TKey key, int amount = 1) + { + if (dictionary.ContainsKey(key)) + dictionary[key] += amount; + else + dictionary[key] = amount; + } + + /// + /// Adds multiple key-value pairs to the dictionary. If a key already exists, it is updated with the new value. + /// + /// The dictionary to update. + /// The key-value pairs to add or update. + public static void AddRange(this IDictionary dictionary, IEnumerable> items) + { + foreach (var kvp in items) + { + dictionary[kvp.Key] = kvp.Value; + } } } } diff --git a/SharpHelpers/SharpHelpers/FileHelper.cs b/SharpHelpers/SharpHelpers/FileHelper.cs index 5b67844..aa99578 100644 --- a/SharpHelpers/SharpHelpers/FileHelper.cs +++ b/SharpHelpers/SharpHelpers/FileHelper.cs @@ -76,28 +76,25 @@ public static long GetFileLenght(this string url) /// public static bool FileInUse(this string filePath) { - FileStream stream = null; + if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath)) return false; try { - var file = new FileInfo(filePath); - stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); + using (File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) + { + // able to open exclusively ⇒ not in use + return false; + } } catch (IOException) { - //the file is unavailable because it is: - //still being written to - //or being processed by another thread - //or does not exist (has already been processed) - return true; + return true; // locked by another process or still being written } - finally + catch (UnauthorizedAccessException) { - stream?.Close(); + // treat as "in use"/not exclusively openable + return true; } - - //file is not locked - return false; } /// diff --git a/SharpHelpers/SharpHelpers/NumericHelper.cs b/SharpHelpers/SharpHelpers/NumericHelper.cs index 76ca8f4..edef609 100644 --- a/SharpHelpers/SharpHelpers/NumericHelper.cs +++ b/SharpHelpers/SharpHelpers/NumericHelper.cs @@ -128,5 +128,64 @@ public static int Abs(this int number) { return Math.Abs(number); } + + /// + /// Checks if the integer is divisible by a specified divisor. + /// + /// The number to check. + /// The divisor. + /// True if divisible; otherwise, false. + public static bool IsDivisibleBy(this int number, int divisor) + { + if (divisor == 0) throw new DivideByZeroException("Divisor cannot be zero."); + return number % divisor == 0; + } + + /// + /// Calculates the percentage this number represents of a total. + /// + /// The partial value. + /// The total value. + /// The percentage as a double. + public static double ToPercentageOf(this int number, int total) + { + if (total == 0) throw new DivideByZeroException("Total cannot be zero."); + return (double)number / total * 100; + } + + /// + /// Checks whether the integer is within the specified inclusive range. + /// + /// The number to check. + /// The minimum bound. + /// The maximum bound. + /// True if within range; otherwise, false. + public static bool IsInRange(this int number, int min, int max) + { + return number >= min && number <= max; + } + + /// + /// Returns the next multiple of the specified factor greater than or equal to the number. + /// + /// The base number. + /// The factor. + /// The next multiple of the factor. + public static int NextMultipleOf(this int number, int factor) + { + if (factor == 0) throw new ArgumentException("Factor cannot be zero."); + int remainder = number % factor; + return remainder == 0 ? number : number + (factor - remainder); + } + + /// + /// Checks whether the integer is a power of two. + /// + /// The number to check. + /// True if the number is a power of two; otherwise, false. + public static bool IsPowerOfTwo(this int number) + { + return number > 0 && (number & (number - 1)) == 0; + } } } diff --git a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectCloneHelper.cs b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectCloneHelper.cs index a67391d..b0de316 100644 --- a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectCloneHelper.cs +++ b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectCloneHelper.cs @@ -14,83 +14,146 @@ public static class ObjectCloneHelper #region Private Properties private const BindingFlags Binding = BindingFlags.Instance | - BindingFlags.NonPublic | BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Public | BindingFlags.FlattenHierarchy; #endregion - public static T Clone(this object istance,ICollection propertyExcludeList = null) + /// + /// Clones an object and returns a deep copy of type T. + /// Excluded properties can be specified via a list of property names. + /// + /// The type of the cloned object. + /// The object to clone. + /// A list of property names to exclude from cloning. + /// A deep copy of the object, or default(T) if the object is null. + public static T Clone(this object instance, ICollection propertyExcludeList = null) { - if (istance == null) + if (instance == null) return default; - return (T) DeepClone(istance,propertyExcludeList); + return (T)DeepClone(instance, propertyExcludeList); } - public static object Clone(this object istance) + /// + /// Clones an object and returns a deep copy. + /// + /// The object to clone. + /// A deep copy of the object. + public static object Clone(this object instance) { - return DeepClone(istance); + return DeepClone(instance); } - #region Privat Method Deep Clone + #region Private Method: DeepClone - // Clone the object Properties and its children recursively - private static object DeepClone(object istance,ICollection propertyExcludeList = null) + /// + /// Recursively clones an object and its children. + /// + /// The object to clone. + /// A list of property names to exclude from cloning. + /// A deep copy of the object. + private static object DeepClone(object instance, ICollection propertyExcludeList = null) { - var desireObjectToBeCloned = istance; + if (instance == null) + return null; - var primaryType = istance.GetType(); + var primaryType = instance.GetType(); + // Handle arrays if (primaryType.IsArray) - return ((Array) desireObjectToBeCloned).Clone(); + return ((Array)instance).Clone(); - object tObject = desireObjectToBeCloned as IList; - if (tObject != null) + // Handle collections (IList) + if (typeof(IList).IsAssignableFrom(primaryType)) { - var properties = primaryType.GetProperties(); - // Get the IList Type of the object - var customList = typeof(List<>).MakeGenericType - ((properties[properties.Length - 1]).PropertyType); - tObject = (IList) Activator.CreateInstance(customList); - var list = (IList) tObject; - // loop throw each object in the list and clone it - foreach (var item in ((IList) desireObjectToBeCloned)) + var listType = typeof(List<>).MakeGenericType(primaryType.GetGenericArguments().FirstOrDefault() ?? typeof(object)); + var listClone = (IList)Activator.CreateInstance(listType); + + foreach (var item in (IList)instance) { - if (item == null) - continue; - var value = DeepClone(item,propertyExcludeList); - list?.Add(value); + listClone.Add(item == null ? null : DeepClone(item, propertyExcludeList)); } + + return listClone; } - else + + // Handle strings + if (primaryType == typeof(string)) + return string.Copy((string)instance); + + // Handle value types (primitives, structs, enums) + if (primaryType.IsValueType || primaryType.IsPrimitive || primaryType.IsEnum) + return instance; + + // Handle complex objects + var clonedObject = FormatterServices.GetUninitializedObject(primaryType); + var fields = primaryType.GetFields(Binding); + + foreach (var field in fields) { - // if the item is a string then Clone it and return it directly. - if (primaryType == typeof(string)) - return (desireObjectToBeCloned as string)?.Clone(); - - // Create an empty object and ignore its construtore. - tObject = FormatterServices.GetUninitializedObject(primaryType); - var fields = desireObjectToBeCloned.GetType().GetFields(Binding); - foreach (var property in fields) + // Skip excluded fields + if (propertyExcludeList != null && propertyExcludeList.Any()) { - if((propertyExcludeList!=null) && (propertyExcludeList.Any())) - if (propertyExcludeList.Contains(property.Name.ExtractBetween("<",">")?.FirstOrDefault())) - continue; - - if (property.IsInitOnly) // Validate if the property is a writable one. + var fieldName = field.Name.ExtractBetween("<", ">")?.FirstOrDefault() ?? field.Name; + if (propertyExcludeList.Contains(fieldName)) continue; - var value = property.GetValue(desireObjectToBeCloned); - if (property.FieldType.IsClass && property.FieldType != typeof(string)) - tObject.GetType().GetField(property.Name, Binding)?.SetValue - (tObject, DeepClone(value,propertyExcludeList)); - else - tObject.GetType().GetField(property.Name, Binding)?.SetValue(tObject, value); } + + // Skip readonly fields + if (field.IsInitOnly) + continue; + + var value = field.GetValue(instance); + + // Clone child objects if they are classes (except strings) + var clonedValue = field.FieldType.IsClass && field.FieldType != typeof(string) + ? DeepClone(value, propertyExcludeList) + : value; + + field.SetValue(clonedObject, clonedValue); } - return tObject; + return clonedObject; } #endregion } -} + + /// + /// Helper extensions for string operations. + /// + public static class StringExtensions + { + /// + /// Extracts a substring between two delimiters. + /// + /// The input string. + /// The starting delimiter. + /// The ending delimiter. + /// An enumerable of substrings found between the delimiters. + public static IEnumerable ExtractBetween(this string input, string startDelimiter, string endDelimiter) + { + if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(startDelimiter) || string.IsNullOrEmpty(endDelimiter)) + return Enumerable.Empty(); + + var results = new List(); + var startIndex = 0; + + while ((startIndex = input.IndexOf(startDelimiter, startIndex)) != -1) + { + startIndex += startDelimiter.Length; + var endIndex = input.IndexOf(endDelimiter, startIndex); + + if (endIndex == -1) + break; + + results.Add(input[startIndex..endIndex]); + startIndex = endIndex + endDelimiter.Length; + } + + return results; + } + } +} \ No newline at end of file diff --git a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectConverterHelper.cs b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectConverterHelper.cs index c61694c..e9fabd0 100755 --- a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectConverterHelper.cs +++ b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectConverterHelper.cs @@ -1,124 +1,184 @@ // (c) 2019 SharpCoding // This code is licensed under MIT license (see LICENSE.txt for details) using System; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; +using System.Text.Json; namespace SharpCoding.SharpHelpers.ObjectExtensions { public static class ObjectConverterHelper { #region Convert to int [Int32] - public static int ToInt32(this object istance) + /// + /// Converts an object to an integer (Int32). Returns a default value if the conversion fails. + /// + /// The object to convert. + /// The default value to return in case of failure. + /// The converted integer or the default value. + public static int ToInt32(this object instance, int defaultValue = 0) { - if (istance == null) return 0; + if (instance == null) return defaultValue; - var valueTemp = istance.ToString(); + var valueTemp = instance.ToString(); - return valueTemp.ToInt32(); + return valueTemp.ToInt32(defaultValue); } - public static int ToInt32(this Enum istance ) + /// + /// Converts an Enum to its integer (Int32) representation. + /// + /// The Enum instance to convert. + /// The integer value of the Enum. + public static int ToInt32(this Enum instance) { - return Convert.ToInt32(istance); + return Convert.ToInt32(instance); } - public static int ToInt32(this string istance) + /// + /// Converts a string to an integer (Int32). Returns a default value if the conversion fails. + /// + /// The string to convert. + /// The default value to return in case of failure. + /// The converted integer or the default value. + public static int ToInt32(this string instance, int defaultValue = 0) { - return int.TryParse(istance, out var result) ? result : default; + return int.TryParse(instance, out var result) ? result : defaultValue; } #endregion #region Convert to long [Int64] - public static long ToInt64(this object istance) + /// + /// Converts an object to a long integer (Int64). Returns a default value if the conversion fails. + /// + /// The object to convert. + /// The default value to return in case of failure. + /// The converted long integer or the default value. + public static long ToInt64(this object instance, long defaultValue = 0) { - if (istance == null) return 0; + if (instance == null) return defaultValue; - var valueTemp = istance.ToString(); + var valueTemp = instance.ToString(); - return valueTemp.ToInt64(); + return valueTemp.ToInt64(defaultValue); } - public static long ToInt64(this Enum istance ) + /// + /// Converts an Enum to its long integer (Int64) representation. + /// + /// The Enum instance to convert. + /// The long integer value of the Enum. + public static long ToInt64(this Enum instance) { - return Convert.ToInt64(istance); + return Convert.ToInt64(instance); } - public static long ToInt64(this string istance) + /// + /// Converts a string to a long integer (Int64). Returns a default value if the conversion fails. + /// + /// The string to convert. + /// The default value to return in case of failure. + /// The converted long integer or the default value. + public static long ToInt64(this string instance, long defaultValue = 0) { - return long.TryParse(istance, out var result) ? result : default; + return long.TryParse(instance, out var result) ? result : defaultValue; } #endregion - public static bool ToBoolean(this string istance) + /// + /// Converts a string to a boolean value. Returns false if the conversion fails. + /// + /// The string to convert. + /// The converted boolean value or false. + public static bool ToBoolean(this string instance) { - return bool.TryParse(istance, out var outValue) && outValue; + return bool.TryParse(instance, out var result) && result; } - - public static DateTime ToDateTime(this string istance) + + /// + /// Converts a string to a DateTime. Returns a default value if the conversion fails. + /// + /// The string to convert. + /// The default value to return in case of failure. + /// The converted DateTime or the default value. + public static DateTime ToDateTime(this string instance, DateTime defaultValue = default) { - return DateTime.TryParse(istance, out var outValue) ? outValue : default; + return DateTime.TryParse(instance, out var result) ? result : defaultValue; } - public static T ToEnum(this string istance) + /// + /// Converts a string to a specified Enum type. Returns a default value if the conversion fails. + /// + /// The Enum type to convert to. + /// The string to convert. + /// The default value to return in case of failure. + /// The converted Enum value or the default value. + public static T ToEnum(this string instance, T defaultValue = default) where T : struct { - return (T) Enum.Parse(typeof (T), istance); + return Enum.TryParse(instance, true, out T result) ? result : defaultValue; } - public static T ToObject(this byte[] istance) where T:class + /// + /// Converts a byte array to an object of a specified type. Returns null if the conversion fails. + /// + /// The type to convert to. + /// The byte array to convert. + /// The converted object or null. + public static T ToObject(this byte[] instance) where T : class { - return (T) istance.ToObject(); + if (instance == null) return null; + + try + { + return JsonSerializer.Deserialize(instance); + } + catch + { + return null; + } } - private static object ToObject(this byte[] istance) + /// + /// Converts an object to a byte array. Returns null if the serialization fails. + /// + /// The object to serialize. + /// The byte array representing the object or null. + public static byte[] ToByteArray(this object obj) { - using (var memoryStream = new MemoryStream(istance)) + if (obj == null) return null; + + try + { + return JsonSerializer.SerializeToUtf8Bytes(obj); + } + catch { - var binaryFormatter = new BinaryFormatter(); - - return binaryFormatter.Deserialize(memoryStream); + return null; } } + /// + /// Converts an integer to its string representation in a specified base (between 2 and 36). + /// Returns an empty string if the base is invalid. + /// + /// The integer to convert. + /// The base to convert to. + /// The string representation of the integer in the specified base. public static string ToBase(this int number, int targetBase) { if (targetBase < 2 || targetBase > 36) return string.Empty; if (targetBase == 10) return number.ToString(); + + var result = string.Empty; var n = targetBase; var q = number; - var rtn = string.Empty; - while (q >= n) + + while (q > 0) { var r = q % n; q /= n; - if (r < 10) { rtn = r + rtn; } - else - { - rtn = Convert.ToChar(r + 55) + rtn; - } + result = (r < 10 ? r.ToString() : ((char)(r + 55)).ToString()) + result; } - if (q < 10) - { rtn = q + rtn; } - else { rtn = Convert.ToChar(q + 55) + rtn; } - - return rtn.PadLeft(5, '0'); - } - /// - /// This method returns the byte array of the specific object - /// - /// - /// - public static byte[] ToByteArray(this object obj) - { - if (obj == null) return null; - - var binaryFormatter = new BinaryFormatter(); - using (var memoryStream = new MemoryStream()) - { - binaryFormatter.Serialize(memoryStream, obj); - return memoryStream.ToArray(); - } + return result; } } -} +} \ No newline at end of file diff --git a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectSerializationhelper.cs b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectSerializationhelper.cs index f3a8c46..f4a7006 100755 --- a/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectSerializationhelper.cs +++ b/SharpHelpers/SharpHelpers/ObjectExtensions/ObjectSerializationhelper.cs @@ -1,54 +1,108 @@ // (c) 2019 SharpCoding // This code is licensed under MIT license (see LICENSE.txt for details) using System.IO; +using System.Text.Json; using System.Xml; using System.Xml.Serialization; -using System.Text.Json; namespace SharpCoding.SharpHelpers.ObjectExtensions { public static class ObjectSerializationHelper { /// - /// This method serializes the specific object to JSON + /// Serializes the specified object to a JSON string. + /// Returns an empty string if the object is null or the serialization fails. /// - /// - /// - public static string SerializeToJson(this object istance) + /// The object to serialize. + /// A JSON string representation of the object. + public static string SerializeToJson(this object instance) { - return istance == null ? string.Empty : JsonSerializer.Serialize(istance); + if (instance == null) return string.Empty; + + try + { + return JsonSerializer.Serialize(instance); + } + catch + { + return string.Empty; + } } /// - /// This method deserializes the JSON to the specific object + /// Deserializes a JSON string to an object of the specified type. + /// Returns null if the string is null, empty, or the deserialization fails. /// - /// - /// - /// - public static T DeserializeFromJson(this string istance) where T : class + /// The type to deserialize to. + /// The JSON string to deserialize. + /// An object of the specified type or null. + public static T DeserializeFromJson(this string instance) where T : class { - return string.IsNullOrEmpty(istance) ? default : JsonSerializer.Deserialize(istance); + if (string.IsNullOrWhiteSpace(instance)) return null; + + try + { + return JsonSerializer.Deserialize(instance); + } + catch + { + return null; + } } /// - /// This method serializes the specific object to XML + /// Serializes the specified object to an XML string. + /// Returns an empty string if the object is null or the serialization fails. /// - /// - /// - public static string SerializeToXml(this object istance) + /// The object to serialize. + /// An XML string representation of the object. + public static string SerializeToXml(this object instance) { - if (istance == null) return string.Empty; + if (instance == null) return string.Empty; - var xmlSerializer = new XmlSerializer(istance.GetType()); + try + { + var xmlSerializer = new XmlSerializer(instance.GetType()); - using (var stringWriter = new StringWriter()) + using (var stringWriter = new StringWriter()) + { + using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true })) + { + xmlSerializer.Serialize(xmlWriter, instance); + return stringWriter.ToString(); + } + } + } + catch { - using (var xmlWriter = XmlWriter.Create(stringWriter)) + return string.Empty; + } + } + + /// + /// Deserializes an XML string to an object of the specified type. + /// Returns null if the string is null, empty, or the deserialization fails. + /// + /// The type to deserialize to. + /// The XML string to deserialize. + /// An object of the specified type or null. + public static T DeserializeFromXml(this string xmlString) where T : class + { + if (string.IsNullOrWhiteSpace(xmlString)) return null; + + try + { + var xmlSerializer = new XmlSerializer(typeof(T)); + + using (var stringReader = new StringReader(xmlString)) { - xmlSerializer.Serialize(xmlWriter, istance); - return stringWriter.ToString(); + return xmlSerializer.Deserialize(stringReader) as T; } } + catch + { + return null; + } } } } diff --git a/SharpHelpers/SharpHelpers/SharpHelpers.csproj b/SharpHelpers/SharpHelpers/SharpHelpers.csproj index ce0c743..7a3dc9c 100644 --- a/SharpHelpers/SharpHelpers/SharpHelpers.csproj +++ b/SharpHelpers/SharpHelpers/SharpHelpers.csproj @@ -45,6 +45,6 @@ - +