NopCommerce开源项目中很基础但是很实用的C# Helper方法
NopCommerce是啥?
nopCommerce是最好的開源電子商務購物 系統。nopCommerce免費提供。今天,它是最好和最流行的ASP.NET電子商務軟件。它已被下載超過180萬次!
nopCommerce是一個完全可定制的購物系統。它穩定且高度可用。nopCommerce是一個開源的電子商務解決方案,它是基于MS SQL 2008(或更高版本)后端數據庫的ASP.NET(MVC)。我們易于使用的購物車解決方案特別適合已經超過現有系統的商家,并可能與您當前的網站托管商或我們的托管合作伙伴一起托管。它擁有開始通過互聯網銷售物理和數字產品所需的一切。
以上解釋引用自該項目的Github :https://github.com/nopSolutions/nopCommerce
因為這幾天沒無法靜心學習該項目的架構,所有只拎出該項目的CommonHelper.cs來談談。
1.E-Mail校驗
#region Fieldsprivate static readonly Regex _emailRegex;//we use EmailValidator from FluentValidation. So let's keep them sync - https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation/Validators/EmailValidator.csprivate const string _emailExpression = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-||_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+([a-z]+|\d|-|\.{0,1}|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])?([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$";#endregion#region Methods/// <summary>/// 檢查Email(是否為空,是否超長,格式是否規范)/// </summary>/// <param name="email">The email.</param>/// <returns></returns>public static string EnsureSubscriberEmailOrThrow(string email){var output = EnsureNotNull(email);output = output.Trim();output = EnsureMaximumLength(output, 255);if (!IsValidEmail(output)){throw new NopException("Email is not valid.");}return output;}/// <summary>/// 用正則表達式校驗Email/// </summary>/// <param name="email">Email to verify</param>/// <returns>true if the string is a valid e-mail address and false if it's not</returns>public static bool IsValidEmail(string email){if (string.IsNullOrEmpty(email))return false;email = email.Trim();return _emailRegex.IsMatch(email);}這個E-mial校驗的方法基本是可以直接拿過來用的,校驗的正則表達式也很全面,需要用的時候可以過來copy。
2.ip地址校驗
/// <summary>/// 檢查該字符串是否是可用的Ip地址/// </summary>/// <param name="ipAddress">IPAddress to verify</param>/// <returns>true if the string is a valid IpAddress and false if it's not</returns>public static bool IsValidIpAddress(string ipAddress){return IPAddress.TryParse(ipAddress, out IPAddress _);}直接使用了系統自帶的IPAddress.TryParse方法,很多小伙伴還不知道吧!
3.產生指定長度的隨機數字字符串
/// <summary>/// 產生一個指定長度的隨機數據字符串/// </summary>/// <param name="length">Length</param>/// <returns>Result string</returns>public static string GenerateRandomDigitCode(int length){var random = new Random();var str = string.Empty;for (var i = 0; i < length; i++)str = string.Concat(str, random.Next(10).ToString());return str;}這里的話,其實我覺得用stringbuild比直接用string更好一點,尤其是當length比較長的時候,可能用stringbuild效率更高一些。
4.產生一個隨機數字
/// <summary>/// 產生一個隨機數/// </summary>/// <param name="min">Minimum number</param>/// <param name="max">Maximum number</param>/// <returns>Result</returns>public static int GenerateRandomInteger(int min = 0, int max = int.MaxValue){var randomNumberBuffer = new byte[10];new RNGCryptoServiceProvider().GetBytes(randomNumberBuffer);return new Random(BitConverter.ToInt32(randomNumberBuffer, 0)).Next(min, max);}當時不懂Random工作原理的時候,覺得這個方法簡直是脫褲子放P,多此一舉,搞得這么麻煩干嘛! 直接Random().Next(min,max)不就產生了一個指定范圍的隨機數嗎?干嘛搞得這么復雜呢?
原來,Random是需要一個隨機數作為“種子”的,當這個種子相同時,那么產生的隨機數也是相同的,有同學肯定會說,我們平時用的時候沒有指定“種子”數據,也能產生我想要的隨機數啊! 其實,當我們沒有指定“種子”的時候,Random時默認以當前時間作為種子的,當高并發訪問的情況下,如果使用時間作為種子數據,這顯然就很有可能產生相同的隨機數,這顯然就不那么“隨機”了,所以該方法看似多余的方法都只是為了利用RNGCryptoServiceProvider().GetBytes()產生一個足夠隨機的byte[],然后再把該byte[]轉換成數字,那么該數字就能基本不會重復了,也就是”種子”不重復,所以隨機數也不會重復了。
5.檢查兩個數組是否相等
/// <summary>/// 檢查兩個數組是否相等/// </summary>/// <typeparam name="T">Type</typeparam>/// <param name="a1">Array 1</param>/// <param name="a2">Array 2</param>/// <returns>Result</returns>public static bool ArraysEqual<T>(T[] a1, T[] a2){//also see Enumerable.SequenceEqual(a1, a2);if (ReferenceEquals(a1, a2))return true;if (a1 == null || a2 == null)return false;if (a1.Length != a2.Length)return false;var comparer = EqualityComparer<T>.Default;for (var i = 0; i < a1.Length; i++){if (!comparer.Equals(a1[i], a2[i])) return false;}return true;}搜先檢測地址引用是否相同,如果相同,肯定時同一個對象,那么相等,然后是檢測時否為空…..?? 代碼很簡單,就不一一說了,我們比較的時候,容易遺忘一些條件,直接走到了for循環最后一步,其實,不到迫不得已,沒不要for循環。
6.給對象的指定屬性賦值
/// <summary>///給對象的指定屬性賦值/// </summary>/// <param name="instance">The object whose property to set.</param>/// <param name="propertyName">The name of the property to set.</param>/// <param name="value">The value to set the property to.</param>public static void SetProperty(object instance, string propertyName, object value){if (instance == null) throw new ArgumentNullException(nameof(instance));if (propertyName == null) throw new ArgumentNullException(nameof(propertyName));var instanceType = instance.GetType();var pi = instanceType.GetProperty(propertyName);if (pi == null)throw new NopException("No property '{0}' found on the instance of type '{1}'.", propertyName, instanceType);if (!pi.CanWrite)throw new NopException("The property '{0}' on the instance of type '{1}' does not have a setter.", propertyName, instanceType);if (value != null && !value.GetType().IsAssignableFrom(pi.PropertyType))value = To(value, pi.PropertyType);pi.SetValue(instance, value, new object[0]);}我也是第一次知道,居然還能這么玩。
7.將一個值轉換成目標類型
/// <summary>/// 將一個值轉換成目標類型。/// </summary>/// <param name="value">The value to convert.</param>/// <param name="destinationType">The type to convert the value to.</param>/// <returns>The converted value.</returns>public static object To(object value, Type destinationType){return To(value, destinationType, CultureInfo.InvariantCulture);}/// <summary>/// 將一個值轉換成目標類型./// </summary>/// <param name="value">The value to convert.</param>/// <param name="destinationType">The type to convert the value to.</param>/// <param name="culture">Culture</param>/// <returns>The converted value.</returns>public static object To(object value, Type destinationType, CultureInfo culture){if (value != null){var sourceType = value.GetType();var destinationConverter = TypeDescriptor.GetConverter(destinationType);if (destinationConverter != null && destinationConverter.CanConvertFrom(value.GetType()))return destinationConverter.ConvertFrom(null, culture, value);var sourceConverter = TypeDescriptor.GetConverter(sourceType);if (sourceConverter != null && sourceConverter.CanConvertTo(destinationType))return sourceConverter.ConvertTo(null, culture, value, destinationType);if (destinationType.IsEnum && value is int)return Enum.ToObject(destinationType, (int)value);if (!destinationType.IsInstanceOfType(value))return Convert.ChangeType(value, destinationType, culture);}return value;}/// <summary>/// 將一個值轉換成目標類型/// </summary>/// <param name="value">The value to convert.</param>/// <typeparam name="T">The type to convert the value to.</typeparam>/// <returns>The converted value.</returns>public static T To<T>(object value){//return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);return (T)To(value, typeof(T));}有了這個方法,我們就不用傻傻想著用Convent….到底Convernt點什么呢?哈哈,直接To<T>(),是不是很帥?
8.刪除目錄
/// <summary>/// 深度優先的遞歸刪除/// </summary>/// <param name="path">Directory path</param>public static void DeleteDirectory(string path){if (string.IsNullOrEmpty(path))throw new ArgumentNullException(path);//find more info about directory deletion//and why we use this approach at https://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-trueforeach (var directory in Directory.GetDirectories(path)){DeleteDirectory(directory);}try{Directory.Delete(path, true);}catch (IOException){Directory.Delete(path, true);}catch (UnauthorizedAccessException){Directory.Delete(path, true);}}一開始,我也不明白為什么要弄得這么復雜,要刪除目錄,直接Directory.Delete(path)就好了不是嗎? 其實不是的,如果目錄不為空,會報System.IO.IOException: The directory is not empty.的錯誤的,所以要遞歸,層層刪除,據說Win系統的資源管理器,刪除目錄,其實就是這個邏輯實現的。
9.獲取兩個Datetime之間的年份間隔
/// <summary>/// 獲取兩個時間之間相差的年份/// </summary>/// <param name="startDate"></param>/// <param name="endDate"></param>/// <returns></returns>public static int GetDifferenceInYears(DateTime startDate, DateTime endDate){//source: http://stackoverflow.com/questions/9/how-do-i-calculate-someones-age-in-c//this assumes you are looking for the western idea of age and not using East Asian reckoning.var age = endDate.Year - startDate.Year;if (startDate > endDate.AddYears(-age))age--;return age;}對,如果endDate.Year -?startDate.Year是不對的,就好像你是去年的8月份出生的,而現在才五月份,那么你現在還不能稱為1歲一樣的道理。同樣的方法還可以用來獲取月、日、時、分、秒的間隔。
10 虛擬路徑轉物理路徑
/// <summary>/// 映射虛擬路徑到物理路徑/// </summary>/// <param name="path">The path to map. E.g. "~/bin"</param>/// <returns>The physical path. E.g. "c:\inetpub\wwwroot\bin"</returns>public static string MapPath(string path){path = path.Replace("~/", "").TrimStart('/').Replace('/', '\\'); ? CommonHelper.BaseDirectory = hostingEnvironment.ContentRootPath; return Path.Combine(BaseDirectory ?? string.Empty, path);}大致就是這么多,可能以上方法大家都知道,但是自己寫出來可能不夠巧妙(老江湖除外),記錄下來,希望對大家有所幫助,也用于自我加深映像。
有興趣的可以去github上下載nopcommerce的源碼來看看。
轉:https://www.cnblogs.com/CoderAyu/p/8982842.html
總結
以上是生活随笔為你收集整理的NopCommerce开源项目中很基础但是很实用的C# Helper方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 民间借贷法律保护的最高年利率是多少
- 下一篇: 比克提尼(说一说比克提尼的简介)