NopCommerce開源項目中很基礎可是很實用的C# Helper方法

剛過了個五一,在杭州處處看房子,不知道杭州最近怎麼了,杭州買房的人這麼多,房價漲得太厲害,這幾年翻倍翻倍地漲,剛過G20,又要亞運會,讓我這樣的剛需用戶買不起,也買不到房子,搞得人心惶惶,太恐怖了,心好累。git

這幾天,由於這件事情感受人都是懵的,沒法靜心學習複雜的東西,因此就看看一些基礎,學習學習NopCommerce的CommonHelper都寫了些啥,看看別人的代碼巧在哪裏,妙在哪裏。github

 

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 Fields

        private 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.cs
        private 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效率更高一些。app

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)不就產生了一個指定範圍的隨機數嗎?幹嗎搞得這麼複雜呢?dom

 

原來,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-true

            foreach (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的源碼來看看。

 

另外,杭州買房,預算有限,杭州城區估計是買不起了,如今在糾結海寧、安吉、德清、桐鄉、桐廬等這樣的周邊地區,若是有杭州有買房經驗的同行大哥但願能給小弟一點指點,哈哈~~

相關文章
相關標籤/搜索