刚过了个五一,在杭州到处看房子,不知道杭州最近怎么了,杭州买房的人这么多,房价涨得太厉害,这几年翻倍翻倍地涨,刚过G20,又要亚运会,让我这样的刚需用户买不起,也买不到房子,搞得人心惶惶,太恐怖了,心好累。

这几天,因为这件事情感觉人都是懵的,无法静心学习复杂的东西,所以就看看一些基础,学习学习NopCommerce的CommonHelper都写了些啥,看看别人的代码巧在哪里,妙在哪里。

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, ); 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 = ; i < length; i++)
str = string.Concat(str, random.Next().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 = , int max = int.MaxValue)
{
var randomNumberBuffer = new byte[];
new RNGCryptoServiceProvider().GetBytes(randomNumberBuffer);
return new Random(BitConverter.ToInt32(randomNumberBuffer, )).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 = ; 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[]);
}

我也是第一次知道,居然还能这么玩。

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的源码来看看。

另外,杭州买房,预算有限,杭州城区估计是买不起了,现在在纠结海宁、安吉、德清、桐乡、桐庐等这样的周边地区,如果有杭州有买房经验的同行大哥希望能给小弟一点指点,哈哈~~

NopCommerce开源项目中很基础但是很实用的C# Helper方法的更多相关文章

  1. [转]C,C++开源项目中的100个Bugs

    [转]C,C++开源项目中的100个Bugs http://tonybai.com/2013/04/10/100-bugs-in-c-cpp-opensource-projects/ 俄罗斯OOO P ...

  2. android studio 使用jar包,arr包和怎么使用githup开源项目中的aar包或module

    我这里的android studio的版本是2.2.3版本 一.现在大家都用android studio了,就有人问怎么使用jar包 其实使用jar包比较简单 直接吧jar放入工程的app目录下的li ...

  3. dotnet 是 前30个增长最快速度的开源项目中排名第一的开发平台

    CNCF 的博客 发了一篇文章 <Update on CNCF and Open Source Project Velocity 2020>,中文翻译参见 2020年CNCF和开源项目开发 ...

  4. Java项目中每一个类都可以有一个main方法

    Java项目中每一个类都可以有一个main方法,但只有一个main方法会被执行,其他main方法可以对类进行单元测试. public class StaticTest { public static ...

  5. 细数Android开源项目中那些频繁使用的并发库中的类

    这篇blog旨在帮助大家 梳理一下前面分析的那些开源代码中喜欢使用的一些类,这对我们真正理解这些项目是有极大好处的,以后遇到类似问题 我们就可以自己模仿他们也写 出类似的代码. 1.ExecutorS ...

  6. C,C++开源项目中的100个Bugs

    俄罗斯OOO Program Verification Systems公司用自己的静态源码分析产品PVS-Studio对一些知名的C/C++开源项目,诸如Apache Http Server.Chro ...

  7. java 基础题 很基础, 很有趣

    都是一些非常非常基础的题,是我最近参加各大IT公司笔试后靠记忆记下来的,经过整理献给与我一样参加各大IT校园招聘的同学们,纯考Java基础功底, 老手们就不用进来了,免得笑话我们这些未出校门的孩纸们, ...

  8. Jquery和Javascript 实际项目中写法基础-弹出窗和弹出层 (4)

     一.实际项目中有很多如下界面效果.    二.该效果可以归结为弹出窗或者弹出层来实现的,为什么这么说?看如下代码:      <!DOCTYPE html> <html> & ...

  9. 项目中lua(基础)

    关于项目中lua任务(某些没弄懂,但lua上耗费时间有点长了不看了) 这段时间看了lua语法和项目中lua应用 .在lua中注册c库,在lua5.2中好像都是注册c库,相当于在lua中定义一个tabl ...

随机推荐

  1. Java基础---Java---正则表达式-----匹配、切割、替换、获取等方法

    正则表达式:符合一定规则的表达式 作用:用于专门操作字符串 特点:用于一些特定的符号来表示一些代码操作,这样就简化书写,主要是学习一些特殊符号的使用 好处:可以简化对字符串的复杂操作. 弊端:符号定义 ...

  2. Android Studio重构之路,我们重新来了解一下Google官方的Android开发工具

    Android Studio重构之路,我们重新来了解一下Google官方的Android开发工具 记得我的第一篇博客就是写Android Studio,但是现在看来还是有些粗糙了,所有重构了一下思路, ...

  3. 【翻译】在Ext JS 6通用应用程序中使用既共享又特定于视图的代码

    原文:Using Both Shared and View-Specific Code in an Ext JS 6 Universal App 在本文,在展示如何编写Ext JS 6通用应用程序代码 ...

  4. SpringMVC项目中启动自加载Listener

    package com.kuman.cartoon.listener; import java.util.List; import org.springframework.beans.factory. ...

  5. Java 中Log4j的使用详情

    Log4j 真的很简单,简单到令人发指的地步.不是要记录日志吗?那就给你一个Log ,然后你用Log 来写东西就行了,先来一个完整类示例: package test; import org.apach ...

  6. 青年菜君与小农女送菜商业模式PK

    青年菜君与小农女送菜商业模式PK   对比项 青年菜君 小农女送菜 优势 劣势 开业 2014年3月3日 2013年9月 渠道 地铁捕获用户 写字楼配送 送货 来店面自取 送货到写字楼 菜君 1.减少 ...

  7. OpenCL异构计算资料收集

    Easy OpenCL with Python   原文  http://www.drdobbs.com/open-source/easy-opencl-with-python/240162614   ...

  8. Linux驱动基础:msm平台,modem等framework加载

    msm平台,AP和CP封装在一起,公用一块内存.所以AP需要负责把整个modem, TZ , rpm等binary拷贝到内存中以供modem等subsystem去运行.那AP这边是怎么分配这些内存,又 ...

  9. 用 boost::multi_index 管理玩家

    用 boost::multi_index 管理玩家(金庆的专栏)网游服务器上的玩家集合需要多种索引:如用ID查找,角色名查找, 用登录时分配的会话ID查找.用boost::multi_index进行玩 ...

  10. android资源库

    原文地址:http://blog.csdn.net/xiechengfa/article/details/38830751 在摸索过程中,GitHub上搜集了很多很棒的Android第三方库,推荐给在 ...