前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.Net Core 最优 MD5 打开方式!初学者建议收藏(支持 SHA1,SHA256,.Net Framework)

.Net Core 最优 MD5 打开方式!初学者建议收藏(支持 SHA1,SHA256,.Net Framework)

作者头像
Edison.Ma
发布2019-08-21 22:03:01
2.1K0
发布2019-08-21 22:03:01
举报
文章被收录于专栏:DotNet Core圈圈
代码语言:javascript
复制
 1:  public static string GetMd5Hash(string input)
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      using (MD5 md5Hash = MD5.Create())
代码语言:javascript
复制
   4:      {
代码语言:javascript
复制
   5:          // Convert the input string to a byte array and compute the hash.
代码语言:javascript
复制
   6:          byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
代码语言:javascript
复制
   7:   
代码语言:javascript
复制
   8:          // Create a new Stringbuilder to collect the bytes
代码语言:javascript
复制
   9:          // and create a string.
代码语言:javascript
复制
  10:          StringBuilder sBuilder = new StringBuilder();
代码语言:javascript
复制
  11:   
代码语言:javascript
复制
  12:          // Loop through each byte of the hashed data
代码语言:javascript
复制
  13:          // and format each one as a hexadecimal string.
代码语言:javascript
复制
  14:          for (int i = 0; i < data.Length; i++)
代码语言:javascript
复制
  15:          {
代码语言:javascript
复制
  16:              sBuilder.Append(data[i].ToString("x2"));
代码语言:javascript
复制
  17:          }
代码语言:javascript
复制
  18:   
代码语言:javascript
复制
  19:          // Return the hexadecimal string.
代码语言:javascript
复制
  20:          return sBuilder.ToString();
代码语言:javascript
复制
  21:      }
代码语言:javascript
复制
  22:  }

这是一段 MSDN 官方的 MD5 示例,例子很简单且很容易理解。但是,这个例子也有很多的问题,首先上例至少创建了 3 个临时缓存区!且每次执行 GetMd5Hash 都会创建一个 MD5 实例,并在方法执行完成后释放它。这些都造成了很大的系统资源浪费和增加了 GC 的压力。

鉴于官方给的 Demo 并不优秀,且网上也没有给出很好使用方式,这里我就拿出我多年使用的 MD5 打开方式,这个方法同时支持 SHA1,SHA256 等,即支持 System.Security.Cryptography 命名空间下的 HashAlgorithm(哈希算法) 实现。也同时支持 .Net Framework 2.0 之后的所有 .Net 平台。

我不想看你的鬼废话,直接给我上最终代码》》》

先说明,这个文章是基于 System.Security.Cryptography 命名空间的实现,不是自己写一个 MD5 算法哦。

现在我们开始,首先我们先定义一个辅助类:

代码语言:javascript
复制
   1:  using System;
代码语言:javascript
复制
   2:  using System.Reflection;
代码语言:javascript
复制
   3:  using System.Runtime.CompilerServices;
代码语言:javascript
复制
   4:  using System.Security.Cryptography;
代码语言:javascript
复制
   5:   
代码语言:javascript
复制
   6:  static class THashAlgorithmInstances<THashAlgorithm> where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   7:  {
代码语言:javascript
复制
   8:      /// <summary>
代码语言:javascript
复制
   9:      /// 线程静态变量。
代码语言:javascript
复制
  10:      /// 即:这个变量在每个线程中都是唯一的。
代码语言:javascript
复制
  11:      /// 再结合泛型类实现:该变量在不同泛型或不同的线程下的值都是不一样的。
代码语言:javascript
复制
  12:      /// 这样做的目的是为了避开多线程问题。
代码语言:javascript
复制
  13:      /// 关于垃圾回收:当 .NET 线程被释放时,程序中的所有线程静态变量都会被回收,GC 回收时同时将释放资源,所以不必担心释放问题,GC 会帮助我们的。
代码语言:javascript
复制
  14:      /// 这里描述的 .NET 线程释放不是指 .NET 线程回收至线程池。很多时候 .NET 的线程在程序关闭之前都不会真正释放,而是在线程池中继续驻留。
代码语言:javascript
复制
  15:      /// 线程唯一真的能避免多线程问题吗?答:多个线程所以用存储空间都不一样,那么脏值就不可能存在,如果这都能出现多线程问题,我直播吃....猪红(本人极其厌恶吃猪红)。
代码语言:javascript
复制
  16:      /// </summary>h
代码语言:javascript
复制
  17:      [ThreadStatic]
代码语言:javascript
复制
  18:      static THashAlgorithm instance;
代码语言:javascript
复制
  19:   
代码语言:javascript
复制
  20:      public static THashAlgorithm Instance => instance ?? Create();
代码语言:javascript
复制
  21:   
代码语言:javascript
复制
  22:      /// <summary>
代码语言:javascript
复制
  23:      /// 寻找 THashAlgorithm 类型下的 Create 静态方法,并执行它。
代码语言:javascript
复制
  24:      /// 如果没找到,则执行 Activator.CreateInstance 调用构造方法创建实例。
代码语言:javascript
复制
  25:      /// 如果 Activator.CreateInstance 方法执行失败,它会抛出异常。
代码语言:javascript
复制
  26:      /// </summary>
代码语言:javascript
复制
  27:      [MethodImpl(MethodImplOptions.NoInlining)]
代码语言:javascript
复制
  28:      static THashAlgorithm Create()
代码语言:javascript
复制
  29:      {
代码语言:javascript
复制
  30:          var createMethod = typeof(THashAlgorithm).GetMethod(
代码语言:javascript
复制
  31:              nameof(HashAlgorithm.Create), // 这段代码同 "Create",低版本 C# 可以替换掉
代码语言:javascript
复制
  32:              BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly,
代码语言:javascript
复制
  33:              Type.DefaultBinder,
代码语言:javascript
复制
  34:              Type.EmptyTypes,
代码语言:javascript
复制
  35:              null);
代码语言:javascript
复制
  36:   
代码语言:javascript
复制
  37:          if (createMethod != null)
代码语言:javascript
复制
  38:          {
代码语言:javascript
复制
  39:              instance = (THashAlgorithm)createMethod.Invoke(null, new object[] { });
代码语言:javascript
复制
  40:          }
代码语言:javascript
复制
  41:          else
代码语言:javascript
复制
  42:          {
代码语言:javascript
复制
  43:              instance = Activator.CreateInstance<THashAlgorithm>();
代码语言:javascript
复制
  44:          }
代码语言:javascript
复制
  45:   
代码语言:javascript
复制
  46:          return instance;
代码语言:javascript
复制
  47:      }
代码语言:javascript
复制
  48:  }

该辅助类帮助我们避开多线程问题,且帮助我们创建指定的 HashAlgorithm 实例。

这里说明一下,HashAlgorithm.ComputeHash (同 MD5.ComputeHash) 方法绝对不是线程安全的!大家使用它的时候必须要注意,在未线程同步下调用同一实例的 ComputeHash 方法得到的结果是错误的!

关于线程唯一和泛型唯一:

还记得老师教我们的时候强调静态变量就是唯一的,可是现在就突然出现了两个反例,与之对立,这让初学者一下子难以接受,其实这也很容易理解的:

首先 [ThreadStatic] 特性我们可以理解为将字段封装为了 ThreadLocal<T>,它在内部区分线程,然后返回不同的值。

然后泛型唯一,举例:我们都知道 List<int> 和 List<string> 它们不是一个类型!那么它们的字段 List<int>.thread_field 和 List<string>.thread_field 也同理不是一个字段,那么它们的值当然也不是同一个啦。

接下来我们再定义实现类:

代码语言:javascript
复制
   1:  public static class HashAlgorithmHelper
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   4:      {
代码语言:javascript
复制
   5:          var data = THashAlgorithmInstances<THashAlgorithm>.Instance.ComputeHash(Encoding.UTF8.GetBytes(input));
代码语言:javascript
复制
   6:   
代码语言:javascript
复制
   7:          var sBuilder = new StringBuilder();
代码语言:javascript
复制
   8:   
代码语言:javascript
复制
   9:          foreach (var item in data)
代码语言:javascript
复制
  10:          {
代码语言:javascript
复制
  11:              sBuilder.Append(item.ToString("x2"));
代码语言:javascript
复制
  12:          }
代码语言:javascript
复制
  13:   
代码语言:javascript
复制
  14:          return sBuilder.ToString();
代码语言:javascript
复制
  15:      }
代码语言:javascript
复制
  16:  }

到这里我们入门级的 MD5 打开方式就完成了,使用方法:HashAlgorithmHelper.ComputeHash<MD5>("Hello World!")

我们来先测试一下:

代码语言:javascript
复制
   1:  static void Main(string[] args)
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      Console.WriteLine(HashAlgorithmHelper.ComputeHash<MD5>("Hello World!"));
代码语言:javascript
复制
   4:      Console.WriteLine(GetMd5Hash("Hello World!"));
代码语言:javascript
复制
   5:   
代码语言:javascript
复制
   6:      while (true)
代码语言:javascript
复制
   7:      {
代码语言:javascript
复制
   8:          var stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
   9:   
代码语言:javascript
复制
  10:          for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
  11:          {
代码语言:javascript
复制
  12:              HashAlgorithmHelper.ComputeHash<MD5>("Hello World!");
代码语言:javascript
复制
  13:          }
代码语言:javascript
复制
  14:   
代码语言:javascript
复制
  15:          Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
  16:   
代码语言:javascript
复制
  17:          stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
  18:   
代码语言:javascript
复制
  19:          for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
  20:          {
代码语言:javascript
复制
  21:              GetMd5Hash("Hello World!");
代码语言:javascript
复制
  22:          }
代码语言:javascript
复制
  23:   
代码语言:javascript
复制
  24:          Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
  25:      }
代码语言:javascript
复制
  26:  }

输出结果:

可以看出我们的性能已经超官方 Demo 近一倍了。

接下来我们将进入进阶级打开方式,我们现在需要自己写一个简单的 byte[] To string 方法,我们先打开 C# 项目的 “允许不安全代码” 选项。

在解决方案中右键项目->属性->生成->勾选“允许不安全代码”。

然后我们在 HashAlgorithmHelper 类中定义新的 ToString 方法。

代码语言:javascript
复制
   1:  static string ToString(byte[] bytes)
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      unsafe
代码语言:javascript
复制
   4:      {
代码语言:javascript
复制
   5:          const int byte_len = 2; // 表示一个 byte 的字符长度。
代码语言:javascript
复制
   6:   
代码语言:javascript
复制
   7:          var str = new string('\0', byte_len * bytes.Length); // 创建一个指定长度的空字符串。
代码语言:javascript
复制
   8:   
代码语言:javascript
复制
   9:          fixed(char* pStr = str)
代码语言:javascript
复制
  10:          {
代码语言:javascript
复制
  11:              var pStr2 = pStr; // fixed pStr 是只读的,所以我们定义一个变量。
代码语言:javascript
复制
  12:   
代码语言:javascript
复制
  13:              foreach (var item in bytes)
代码语言:javascript
复制
  14:              {
代码语言:javascript
复制
  15:                  *pStr2 = Digitals[item >> 4/* byte high */]; ++pStr2;
代码语言:javascript
复制
  16:                  *pStr2 = Digitals[item & 15/* byte low */]; ++pStr2;
代码语言:javascript
复制
  17:              }
代码语言:javascript
复制
  18:          }
代码语言:javascript
复制
  19:   
代码语言:javascript
复制
  20:          return str;
代码语言:javascript
复制
  21:      }
代码语言:javascript
复制
  22:  }

然后我们修改 ComputeHash 方法为如下:

代码语言:javascript
复制
   1:  public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      var bytes = Encoding.UTF8.GetBytes(input);
代码语言:javascript
复制
   4:   
代码语言:javascript
复制
   5:      var data = THashAlgorithmInstances<THashAlgorithm>.Instance.ComputeHash(bytes);
代码语言:javascript
复制
   6:   
代码语言:javascript
复制
   7:      return ToString(data);
代码语言:javascript
复制
   8:  }

现在我们再测试就会发现已经比官方 Demo 快 4 倍了!现在这个 MD5 打开方式已经适合绝大多数人了,如果您不喜欢不安全代码,也可以用数组代替,效率只差一丢丢而已,该方式我会在下方给出完整代码。

接下来我们使用 .Net Core 以最优的方式打开,我们修改 HashAlgorithmHelper 为如下:(这里就不再支持 .Net Framework 了)

代码语言:javascript
复制
   1:  public static class HashAlgorithmHelper
代码语言:javascript
复制
   2:  {
代码语言:javascript
复制
   3:      static readonly char[] Digitals = {'0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
代码语言:javascript
复制
   4:   
代码语言:javascript
复制
   5:      // 在这个函数里要用到的 bytes 成员 ReadOnlySpan<byte> 与 byte[] 的一致,所以我们只需要修改参数类型即可。
代码语言:javascript
复制
   6:      static string ToString(ReadOnlySpan<byte> bytes)
代码语言:javascript
复制
   7:      {
代码语言:javascript
复制
   8:          unsafe
代码语言:javascript
复制
   9:          {
代码语言:javascript
复制
  10:              const int byte_len = 2; // 表示一个 byte 的字符长度。
代码语言:javascript
复制
  11:   
代码语言:javascript
复制
  12:              var str = new string('\0', byte_len * bytes.Length);
代码语言:javascript
复制
  13:   
代码语言:javascript
复制
  14:              fixed(char* pStr = str)
代码语言:javascript
复制
  15:              {
代码语言:javascript
复制
  16:                  var pStr2 = pStr; // fixed pStr 是只读的,所以我们定义一个变量。
代码语言:javascript
复制
  17:   
代码语言:javascript
复制
  18:                  foreach (var item in bytes)
代码语言:javascript
复制
  19:                  {
代码语言:javascript
复制
  20:                      *pStr2 = Digitals[item >> 4/* byte high */]; ++pStr2;
代码语言:javascript
复制
  21:                      *pStr2 = Digitals[item & 15/* byte high */]; ++pStr2;
代码语言:javascript
复制
  22:                  }
代码语言:javascript
复制
  23:              }
代码语言:javascript
复制
  24:   
代码语言:javascript
复制
  25:              return str;
代码语言:javascript
复制
  26:          }
代码语言:javascript
复制
  27:      }
代码语言:javascript
复制
  28:   
代码语言:javascript
复制
  29:      public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
  30:      {
代码语言:javascript
复制
  31:          var instance = THashAlgorithmInstances<THashAlgorithm>.Instance; // 避免二次取值,微微提高效率(自我感觉)。
代码语言:javascript
复制
  32:          var encoding = Encoding.UTF8;
代码语言:javascript
复制
  33:   
代码语言:javascript
复制
  34:          // 我们在这里声明一个足量的 byte 数组,足以容下字符串的 utf-8 字节码和 hash 值的字节码。
代码语言:javascript
复制
  35:          var bytes = new byte[Encoding.UTF8.GetMaxByteCount(Math.Max(input.Length, instance.HashSize / 2))];
代码语言:javascript
复制
  36:   
代码语言:javascript
复制
  37:          var bytesCount = encoding.GetBytes(input, bytes);
代码语言:javascript
复制
  38:   
代码语言:javascript
复制
  39:          var source = new ReadOnlySpan<byte>(bytes, 0, bytesCount); // source: utf-8 bytes region.
代码语言:javascript
复制
  40:          var destination = new Span<byte>(bytes, bytesCount, bytes.Length - bytesCount); // destination: buffer region.
代码语言:javascript
复制
  41:   
代码语言:javascript
复制
  42:          if (bytes.Length - bytesCount > instance.HashSize && instance.TryComputeHash(source, destination, out var bytesWritten))
代码语言:javascript
复制
  43:          {
代码语言:javascript
复制
  44:              return ToString(destination.Slice(0, bytesWritten));
代码语言:javascript
复制
  45:          }
代码语言:javascript
复制
  46:          else
代码语言:javascript
复制
  47:          {
代码语言:javascript
复制
  48:              // 通常情况下这里就很有可能抛出异常了,但是我们封装工具方法必须有一个原则,我们尽量不要自行抛出。
代码语言:javascript
复制
  49:              // 用户的参数执行到这里我们依然调用 HashAlgorithm.ComputeHash,由它内部抛出异常。这样可以避免很多问题和歧义。
代码语言:javascript
复制
  50:              return ToString(instance.ComputeHash(bytes, 0, bytesCount));
代码语言:javascript
复制
  51:          }
代码语言:javascript
复制
  52:      }
代码语言:javascript
复制
  53:  }

我们再次测试,结果如下:

现在我们已经超官方示例达 5 倍了!这就是最终版本了。

最后附上各个版本实现的完整代码:

Core 2.1+ 包含不安全代码版本:

代码语言:javascript
复制
   1:  using System;
代码语言:javascript
复制
   2:  using System.Diagnostics;
代码语言:javascript
复制
   3:  using System.Reflection;
代码语言:javascript
复制
   4:  using System.Runtime.CompilerServices;
代码语言:javascript
复制
   5:  using System.Security.Cryptography;
代码语言:javascript
复制
   6:  using System.Text;
代码语言:javascript
复制
   7:   
代码语言:javascript
复制
   8:  static class THashAlgorithmInstances<THashAlgorithm> where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   9:  {
代码语言:javascript
复制
  10:      /// <summary>
代码语言:javascript
复制
  11:      /// 线程静态变量。
代码语言:javascript
复制
  12:      /// 即:这个变量在每个线程中都是唯一的。
代码语言:javascript
复制
  13:      /// 再结合泛型类实现了该变量在不同泛型或不同的线程先的变量都是唯一的。
代码语言:javascript
复制
  14:      /// 这样做的目的是为了避开多线程问题。
代码语言:javascript
复制
  15:      /// </summary>
代码语言:javascript
复制
  16:      [ThreadStatic]
代码语言:javascript
复制
  17:      static THashAlgorithm instance;
代码语言:javascript
复制
  18:   
代码语言:javascript
复制
  19:      public static THashAlgorithm Instance => instance ?? Create();
代码语言:javascript
复制
  20:   
代码语言:javascript
复制
  21:      /// <summary>
代码语言:javascript
复制
  22:      /// 寻找 THashAlgorithm 类型下的 Create 静态方法,并执行它。
代码语言:javascript
复制
  23:      /// 如果没找到,则执行 Activator.CreateInstance 调用构造方法创建实例。
代码语言:javascript
复制
  24:      /// 如果 Activator.CreateInstance 方法执行失败,它会抛出异常。
代码语言:javascript
复制
  25:      /// </summary>
代码语言:javascript
复制
  26:      [MethodImpl(MethodImplOptions.NoInlining)]
代码语言:javascript
复制
  27:      static THashAlgorithm Create()
代码语言:javascript
复制
  28:      {
代码语言:javascript
复制
  29:          var createMethod = typeof(THashAlgorithm).GetMethod(
代码语言:javascript
复制
  30:              nameof(HashAlgorithm.Create), // 这段代码同 "Create",低版本 C# 可以替换掉
代码语言:javascript
复制
  31:              BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly,
代码语言:javascript
复制
  32:              Type.DefaultBinder,
代码语言:javascript
复制
  33:              Type.EmptyTypes,
代码语言:javascript
复制
  34:              null);
代码语言:javascript
复制
  35:   
代码语言:javascript
复制
  36:          if (createMethod != null)
代码语言:javascript
复制
  37:          {
代码语言:javascript
复制
  38:              instance = (THashAlgorithm)createMethod.Invoke(null, new object[] { });
代码语言:javascript
复制
  39:          }
代码语言:javascript
复制
  40:          else
代码语言:javascript
复制
  41:          {
代码语言:javascript
复制
  42:              instance = Activator.CreateInstance<THashAlgorithm>();
代码语言:javascript
复制
  43:          }
代码语言:javascript
复制
  44:   
代码语言:javascript
复制
  45:          return instance;
代码语言:javascript
复制
  46:      }
代码语言:javascript
复制
  47:  }
代码语言:javascript
复制
  48:   
代码语言:javascript
复制
  49:  public static class HashAlgorithmHelper
代码语言:javascript
复制
  50:  {
代码语言:javascript
复制
  51:      static readonly char[] Digitals = {'0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
代码语言:javascript
复制
  52:   
代码语言:javascript
复制
  53:      static string ToString(ReadOnlySpan<byte> bytes)
代码语言:javascript
复制
  54:      {
代码语言:javascript
复制
  55:          unsafe
代码语言:javascript
复制
  56:          {
代码语言:javascript
复制
  57:              const int byte_len = 2; // 表示一个 byte 的字符长度。
代码语言:javascript
复制
  58:   
代码语言:javascript
复制
  59:              var str = new string('\0', byte_len * bytes.Length);
代码语言:javascript
复制
  60:   
代码语言:javascript
复制
  61:              fixed(char* pStr = str)
代码语言:javascript
复制
  62:              {
代码语言:javascript
复制
  63:                  var pStr2 = pStr; // fixed pStr 是只读的,所以我们定义一个变量。
代码语言:javascript
复制
  64:   
代码语言:javascript
复制
  65:                  foreach (var item in bytes)
代码语言:javascript
复制
  66:                  {
代码语言:javascript
复制
  67:                      *pStr2 = Digitals[item >> 4/* byte high */]; ++pStr2;
代码语言:javascript
复制
  68:                      *pStr2 = Digitals[item & 15/* byte high */]; ++pStr2;
代码语言:javascript
复制
  69:                  }
代码语言:javascript
复制
  70:              }
代码语言:javascript
复制
  71:   
代码语言:javascript
复制
  72:              return str;
代码语言:javascript
复制
  73:          }
代码语言:javascript
复制
  74:      }
代码语言:javascript
复制
  75:   
代码语言:javascript
复制
  76:      public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
  77:      {
代码语言:javascript
复制
  78:          var instance = THashAlgorithmInstances<THashAlgorithm>.Instance;
代码语言:javascript
复制
  79:          var encoding = Encoding.UTF8;
代码语言:javascript
复制
  80:   
代码语言:javascript
复制
  81:          var bytes = new byte[Encoding.UTF8.GetMaxByteCount(Math.Max(input.Length, instance.HashSize / 2))];
代码语言:javascript
复制
  82:   
代码语言:javascript
复制
  83:          var bytesCount = encoding.GetBytes(input, bytes);
代码语言:javascript
复制
  84:   
代码语言:javascript
复制
  85:          var source = new ReadOnlySpan<byte>(bytes, 0, bytesCount); // source: utf-8 bytes region.
代码语言:javascript
复制
  86:          var destination = new Span<byte>(bytes, bytesCount, bytes.Length - bytesCount); // destination: buffer region.
代码语言:javascript
复制
  87:   
代码语言:javascript
复制
  88:          if (bytes.Length - bytesCount > instance.HashSize && instance.TryComputeHash(source, destination, out var bytesWritten))
代码语言:javascript
复制
  89:          {
代码语言:javascript
复制
  90:              return ToString(destination.Slice(0, bytesWritten));
代码语言:javascript
复制
  91:          }
代码语言:javascript
复制
  92:          else
代码语言:javascript
复制
  93:          {
代码语言:javascript
复制
  94:              return ToString(instance.ComputeHash(bytes, 0, bytesCount));
代码语言:javascript
复制
  95:          }
代码语言:javascript
复制
  96:      }
代码语言:javascript
复制
  97:  }
代码语言:javascript
复制
  98:   
代码语言:javascript
复制
  99:  class Program
代码语言:javascript
复制
 100:  {
代码语言:javascript
复制
 101:      public static string GetMd5Hash(string input)
代码语言:javascript
复制
 102:      {
代码语言:javascript
复制
 103:          using (MD5 md5Hash = MD5.Create())
代码语言:javascript
复制
 104:          {
代码语言:javascript
复制
 105:              // Convert the input string to a byte array and compute the hash.
代码语言:javascript
复制
 106:              byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
代码语言:javascript
复制
 107:   
代码语言:javascript
复制
 108:              // Create a new Stringbuilder to collect the bytes
代码语言:javascript
复制
 109:              // and create a string.
代码语言:javascript
复制
 110:              StringBuilder sBuilder = new StringBuilder();
代码语言:javascript
复制
 111:   
代码语言:javascript
复制
 112:              // Loop through each byte of the hashed data
代码语言:javascript
复制
 113:              // and format each one as a hexadecimal string.
代码语言:javascript
复制
 114:              for (int i = 0; i < data.Length; i++)
代码语言:javascript
复制
 115:              {
代码语言:javascript
复制
 116:                  sBuilder.Append(data[i].ToString("x2"));
代码语言:javascript
复制
 117:              }
代码语言:javascript
复制
 118:   
代码语言:javascript
复制
 119:              // Return the hexadecimal string.
代码语言:javascript
复制
 120:              return sBuilder.ToString();
代码语言:javascript
复制
 121:          }
代码语言:javascript
复制
 122:      }
代码语言:javascript
复制
 123:   
代码语言:javascript
复制
 124:      static void Main(string[] args)
代码语言:javascript
复制
 125:      {
代码语言:javascript
复制
 126:          Console.WriteLine(HashAlgorithmHelper.ComputeHash<MD5>("Hello World!"));
代码语言:javascript
复制
 127:          Console.WriteLine(GetMd5Hash("Hello World!"));
代码语言:javascript
复制
 128:   
代码语言:javascript
复制
 129:          while (true)
代码语言:javascript
复制
 130:          {
代码语言:javascript
复制
 131:              var stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 132:   
代码语言:javascript
复制
 133:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 134:              {
代码语言:javascript
复制
 135:                  HashAlgorithmHelper.ComputeHash<MD5>("Hello World!");
代码语言:javascript
复制
 136:              }
代码语言:javascript
复制
 137:   
代码语言:javascript
复制
 138:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 139:   
代码语言:javascript
复制
 140:              stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 141:   
代码语言:javascript
复制
 142:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 143:              {
代码语言:javascript
复制
 144:                  GetMd5Hash("Hello World!");
代码语言:javascript
复制
 145:              }
代码语言:javascript
复制
 146:   
代码语言:javascript
复制
 147:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 148:          }
代码语言:javascript
复制
 149:      }
代码语言:javascript
复制
 150:  }

包含不安全代码的通用版本:

代码语言:javascript
复制
   1:  using System;
代码语言:javascript
复制
   2:  using System.Diagnostics;
代码语言:javascript
复制
   3:  using System.Reflection;
代码语言:javascript
复制
   4:  using System.Runtime.CompilerServices;
代码语言:javascript
复制
   5:  using System.Security.Cryptography;
代码语言:javascript
复制
   6:  using System.Text;
代码语言:javascript
复制
   7:   
代码语言:javascript
复制
   8:  static class THashAlgorithmInstances<THashAlgorithm> where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   9:  {
代码语言:javascript
复制
  10:      /// <summary>
代码语言:javascript
复制
  11:      /// 线程静态变量。
代码语言:javascript
复制
  12:      /// 即:这个变量在每个线程中都是唯一的。
代码语言:javascript
复制
  13:      /// 再结合泛型类实现了该变量在不同泛型或不同的线程先的变量都是唯一的。
代码语言:javascript
复制
  14:      /// 这样做的目的是为了避开多线程问题。
代码语言:javascript
复制
  15:      /// </summary>
代码语言:javascript
复制
  16:      [ThreadStatic]
代码语言:javascript
复制
  17:      static THashAlgorithm instance;
代码语言:javascript
复制
  18:   
代码语言:javascript
复制
  19:      public static THashAlgorithm Instance => instance ?? Create();
代码语言:javascript
复制
  20:   
代码语言:javascript
复制
  21:      /// <summary>
代码语言:javascript
复制
  22:      /// 寻找 THashAlgorithm 类型下的 Create 静态方法,并执行它。
代码语言:javascript
复制
  23:      /// 如果没找到,则执行 Activator.CreateInstance 调用构造方法创建实例。
代码语言:javascript
复制
  24:      /// 如果 Activator.CreateInstance 方法执行失败,它会抛出异常。
代码语言:javascript
复制
  25:      /// </summary>
代码语言:javascript
复制
  26:      [MethodImpl(MethodImplOptions.NoInlining)]
代码语言:javascript
复制
  27:      static THashAlgorithm Create()
代码语言:javascript
复制
  28:      {
代码语言:javascript
复制
  29:          var createMethod = typeof(THashAlgorithm).GetMethod(
代码语言:javascript
复制
  30:              nameof(HashAlgorithm.Create), // 这段代码同 "Create",低版本 C# 可以替换掉
代码语言:javascript
复制
  31:              BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly,
代码语言:javascript
复制
  32:              Type.DefaultBinder,
代码语言:javascript
复制
  33:              Type.EmptyTypes,
代码语言:javascript
复制
  34:              null);
代码语言:javascript
复制
  35:   
代码语言:javascript
复制
  36:          if (createMethod != null)
代码语言:javascript
复制
  37:          {
代码语言:javascript
复制
  38:              instance = (THashAlgorithm)createMethod.Invoke(null, new object[] { });
代码语言:javascript
复制
  39:          }
代码语言:javascript
复制
  40:          else
代码语言:javascript
复制
  41:          {
代码语言:javascript
复制
  42:              instance = Activator.CreateInstance<THashAlgorithm>();
代码语言:javascript
复制
  43:          }
代码语言:javascript
复制
  44:   
代码语言:javascript
复制
  45:          return instance;
代码语言:javascript
复制
  46:      }
代码语言:javascript
复制
  47:  }
代码语言:javascript
复制
  48:   
代码语言:javascript
复制
  49:  public static class HashAlgorithmHelper
代码语言:javascript
复制
  50:  {
代码语言:javascript
复制
  51:      static readonly char[] Digitals = {'0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
代码语言:javascript
复制
  52:   
代码语言:javascript
复制
  53:      static string ToString(byte[] bytes)
代码语言:javascript
复制
  54:      {
代码语言:javascript
复制
  55:          unsafe
代码语言:javascript
复制
  56:          {
代码语言:javascript
复制
  57:              const int byte_len = 2; // 表示一个 byte 的字符长度。
代码语言:javascript
复制
  58:   
代码语言:javascript
复制
  59:              var str = new string('\0', byte_len * bytes.Length);
代码语言:javascript
复制
  60:   
代码语言:javascript
复制
  61:              fixed(char* pStr = str)
代码语言:javascript
复制
  62:              {
代码语言:javascript
复制
  63:                  var pStr2 = pStr; // fixed pStr 是只读的,所以我们定义一个变量。
代码语言:javascript
复制
  64:   
代码语言:javascript
复制
  65:                  foreach (var item in bytes)
代码语言:javascript
复制
  66:                  {
代码语言:javascript
复制
  67:                      *pStr2 = Digitals[item >> 4/* byte high */]; ++pStr2;
代码语言:javascript
复制
  68:                      *pStr2 = Digitals[item & 15/* byte high */]; ++pStr2;
代码语言:javascript
复制
  69:                  }
代码语言:javascript
复制
  70:              }
代码语言:javascript
复制
  71:   
代码语言:javascript
复制
  72:              return str;
代码语言:javascript
复制
  73:          }
代码语言:javascript
复制
  74:      }
代码语言:javascript
复制
  75:   
代码语言:javascript
复制
  76:      public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
  77:      {
代码语言:javascript
复制
  78:          var bytes = Encoding.UTF8.GetBytes(input);
代码语言:javascript
复制
  79:   
代码语言:javascript
复制
  80:          return ToString(THashAlgorithmInstances<THashAlgorithm>.Instance.ComputeHash(bytes));
代码语言:javascript
复制
  81:      }
代码语言:javascript
复制
  82:  }
代码语言:javascript
复制
  83:   
代码语言:javascript
复制
  84:  class Program
代码语言:javascript
复制
  85:  {
代码语言:javascript
复制
  86:      public static string GetMd5Hash(string input)
代码语言:javascript
复制
  87:      {
代码语言:javascript
复制
  88:          using (MD5 md5Hash = MD5.Create())
代码语言:javascript
复制
  89:          {
代码语言:javascript
复制
  90:              // Convert the input string to a byte array and compute the hash.
代码语言:javascript
复制
  91:              byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
代码语言:javascript
复制
  92:   
代码语言:javascript
复制
  93:              // Create a new Stringbuilder to collect the bytes
代码语言:javascript
复制
  94:              // and create a string.
代码语言:javascript
复制
  95:              StringBuilder sBuilder = new StringBuilder();
代码语言:javascript
复制
  96:   
代码语言:javascript
复制
  97:              // Loop through each byte of the hashed data
代码语言:javascript
复制
  98:              // and format each one as a hexadecimal string.
代码语言:javascript
复制
  99:              for (int i = 0; i < data.Length; i++)
代码语言:javascript
复制
 100:              {
代码语言:javascript
复制
 101:                  sBuilder.Append(data[i].ToString("x2"));
代码语言:javascript
复制
 102:              }
代码语言:javascript
复制
 103:   
代码语言:javascript
复制
 104:              // Return the hexadecimal string.
代码语言:javascript
复制
 105:              return sBuilder.ToString();
代码语言:javascript
复制
 106:          }
代码语言:javascript
复制
 107:      }
代码语言:javascript
复制
 108:   
代码语言:javascript
复制
 109:      static void Main(string[] args)
代码语言:javascript
复制
 110:      {
代码语言:javascript
复制
 111:          Console.WriteLine(HashAlgorithmHelper.ComputeHash<MD5>("Hello World!"));
代码语言:javascript
复制
 112:          Console.WriteLine(GetMd5Hash("Hello World!"));
代码语言:javascript
复制
 113:   
代码语言:javascript
复制
 114:          while (true)
代码语言:javascript
复制
 115:          {
代码语言:javascript
复制
 116:              var stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 117:   
代码语言:javascript
复制
 118:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 119:              {
代码语言:javascript
复制
 120:                  HashAlgorithmHelper.ComputeHash<MD5>("Hello World!");
代码语言:javascript
复制
 121:              }
代码语言:javascript
复制
 122:   
代码语言:javascript
复制
 123:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 124:   
代码语言:javascript
复制
 125:              stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 126:   
代码语言:javascript
复制
 127:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 128:              {
代码语言:javascript
复制
 129:                  GetMd5Hash("Hello World!");
代码语言:javascript
复制
 130:              }
代码语言:javascript
复制
 131:   
代码语言:javascript
复制
 132:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 133:          }
代码语言:javascript
复制
 134:      }
代码语言:javascript
复制
 135:  }

不包含不安全代码的通用版本:

代码语言:javascript
复制
   1:  using System;
代码语言:javascript
复制
   2:  using System.Diagnostics;
代码语言:javascript
复制
   3:  using System.Reflection;
代码语言:javascript
复制
   4:  using System.Runtime.CompilerServices;
代码语言:javascript
复制
   5:  using System.Security.Cryptography;
代码语言:javascript
复制
   6:  using System.Text;
代码语言:javascript
复制
   7:   
代码语言:javascript
复制
   8:  static class THashAlgorithmInstances<THashAlgorithm> where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
   9:  {
代码语言:javascript
复制
  10:      /// <summary>
代码语言:javascript
复制
  11:      /// 线程静态变量。
代码语言:javascript
复制
  12:      /// 即:这个变量在每个线程中都是唯一的。
代码语言:javascript
复制
  13:      /// 再结合泛型类实现了该变量在不同泛型或不同的线程先的变量都是唯一的。
代码语言:javascript
复制
  14:      /// 这样做的目的是为了避开多线程问题。
代码语言:javascript
复制
  15:      /// </summary>
代码语言:javascript
复制
  16:      [ThreadStatic]
代码语言:javascript
复制
  17:      static THashAlgorithm instance;
代码语言:javascript
复制
  18:   
代码语言:javascript
复制
  19:      public static THashAlgorithm Instance => instance ?? Create();
代码语言:javascript
复制
  20:   
代码语言:javascript
复制
  21:      /// <summary>
代码语言:javascript
复制
  22:      /// 寻找 THashAlgorithm 类型下的 Create 静态方法,并执行它。
代码语言:javascript
复制
  23:      /// 如果没找到,则执行 Activator.CreateInstance 调用构造方法创建实例。
代码语言:javascript
复制
  24:      /// 如果 Activator.CreateInstance 方法执行失败,它会抛出异常。
代码语言:javascript
复制
  25:      /// </summary>
代码语言:javascript
复制
  26:      [MethodImpl(MethodImplOptions.NoInlining)]
代码语言:javascript
复制
  27:      static THashAlgorithm Create()
代码语言:javascript
复制
  28:      {
代码语言:javascript
复制
  29:          var createMethod = typeof(THashAlgorithm).GetMethod(
代码语言:javascript
复制
  30:              nameof(HashAlgorithm.Create), // 这段代码同 "Create",低版本 C# 可以替换掉
代码语言:javascript
复制
  31:              BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly,
代码语言:javascript
复制
  32:              Type.DefaultBinder,
代码语言:javascript
复制
  33:              Type.EmptyTypes,
代码语言:javascript
复制
  34:              null);
代码语言:javascript
复制
  35:   
代码语言:javascript
复制
  36:          if (createMethod != null)
代码语言:javascript
复制
  37:          {
代码语言:javascript
复制
  38:              instance = (THashAlgorithm)createMethod.Invoke(null, new object[] { });
代码语言:javascript
复制
  39:          }
代码语言:javascript
复制
  40:          else
代码语言:javascript
复制
  41:          {
代码语言:javascript
复制
  42:              instance = Activator.CreateInstance<THashAlgorithm>();
代码语言:javascript
复制
  43:          }
代码语言:javascript
复制
  44:   
代码语言:javascript
复制
  45:          return instance;
代码语言:javascript
复制
  46:      }
代码语言:javascript
复制
  47:  }
代码语言:javascript
复制
  48:   
代码语言:javascript
复制
  49:  public static class HashAlgorithmHelper
代码语言:javascript
复制
  50:  {
代码语言:javascript
复制
  51:      static readonly char[] Digitals = {'0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
代码语言:javascript
复制
  52:   
代码语言:javascript
复制
  53:      static string ToString(byte[] bytes)
代码语言:javascript
复制
  54:      {
代码语言:javascript
复制
  55:          const int byte_len = 2; // 表示一个 byte 的字符长度。
代码语言:javascript
复制
  56:   
代码语言:javascript
复制
  57:          var chars = new char[byte_len * bytes.Length];
代码语言:javascript
复制
  58:   
代码语言:javascript
复制
  59:          var index = 0;
代码语言:javascript
复制
  60:   
代码语言:javascript
复制
  61:          foreach (var item in bytes)
代码语言:javascript
复制
  62:          {
代码语言:javascript
复制
  63:              chars[index] = Digitals[item >> 4/* byte high */]; ++index;
代码语言:javascript
复制
  64:              chars[index] = Digitals[item & 15/* byte high */]; ++index;
代码语言:javascript
复制
  65:          }
代码语言:javascript
复制
  66:   
代码语言:javascript
复制
  67:          return new string(chars);
代码语言:javascript
复制
  68:      }
代码语言:javascript
复制
  69:   
代码语言:javascript
复制
  70:      public static string ComputeHash<THashAlgorithm>(string input) where THashAlgorithm : HashAlgorithm
代码语言:javascript
复制
  71:      {
代码语言:javascript
复制
  72:          var bytes = Encoding.UTF8.GetBytes(input);
代码语言:javascript
复制
  73:   
代码语言:javascript
复制
  74:          return ToString(THashAlgorithmInstances<THashAlgorithm>.Instance.ComputeHash(bytes));
代码语言:javascript
复制
  75:      }
代码语言:javascript
复制
  76:  }
代码语言:javascript
复制
  77:   
代码语言:javascript
复制
  78:  class Program
代码语言:javascript
复制
  79:  {
代码语言:javascript
复制
  80:      public static string GetMd5Hash(string input)
代码语言:javascript
复制
  81:      {
代码语言:javascript
复制
  82:          using (MD5 md5Hash = MD5.Create())
代码语言:javascript
复制
  83:          {
代码语言:javascript
复制
  84:              // Convert the input string to a byte array and compute the hash.
代码语言:javascript
复制
  85:              byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
代码语言:javascript
复制
  86:   
代码语言:javascript
复制
  87:              // Create a new Stringbuilder to collect the bytes
代码语言:javascript
复制
  88:              // and create a string.
代码语言:javascript
复制
  89:              StringBuilder sBuilder = new StringBuilder();
代码语言:javascript
复制
  90:   
代码语言:javascript
复制
  91:              // Loop through each byte of the hashed data
代码语言:javascript
复制
  92:              // and format each one as a hexadecimal string.
代码语言:javascript
复制
  93:              for (int i = 0; i < data.Length; i++)
代码语言:javascript
复制
  94:              {
代码语言:javascript
复制
  95:                  sBuilder.Append(data[i].ToString("x2"));
代码语言:javascript
复制
  96:              }
代码语言:javascript
复制
  97:   
代码语言:javascript
复制
  98:              // Return the hexadecimal string.
代码语言:javascript
复制
  99:              return sBuilder.ToString();
代码语言:javascript
复制
 100:          }
代码语言:javascript
复制
 101:      }
代码语言:javascript
复制
 102:   
代码语言:javascript
复制
 103:      static void Main(string[] args)
代码语言:javascript
复制
 104:      {
代码语言:javascript
复制
 105:          Console.WriteLine(HashAlgorithmHelper.ComputeHash<MD5>("Hello World!"));
代码语言:javascript
复制
 106:          Console.WriteLine(GetMd5Hash("Hello World!"));
代码语言:javascript
复制
 107:   
代码语言:javascript
复制
 108:          while (true)
代码语言:javascript
复制
 109:          {
代码语言:javascript
复制
 110:              var stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 111:   
代码语言:javascript
复制
 112:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 113:              {
代码语言:javascript
复制
 114:                  HashAlgorithmHelper.ComputeHash<MD5>("Hello World!");
代码语言:javascript
复制
 115:              }
代码语言:javascript
复制
 116:   
代码语言:javascript
复制
 117:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 118:   
代码语言:javascript
复制
 119:              stopwatch = Stopwatch.StartNew();
代码语言:javascript
复制
 120:   
代码语言:javascript
复制
 121:              for (int i = 0; i < 1000000; i++)
代码语言:javascript
复制
 122:              {
代码语言:javascript
复制
 123:                  GetMd5Hash("Hello World!");
代码语言:javascript
复制
 124:              }
代码语言:javascript
复制
 125:   
代码语言:javascript
复制
 126:              Console.WriteLine(stopwatch.ElapsedMilliseconds);
代码语言:javascript
复制
 127:          }
代码语言:javascript
复制
 128:      }
代码语言:javascript
复制
 129:  }

不包含不安全代码通用版本的性能:(性能依然极佳,建议使用此版本)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet技术平台 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档