可排序的 COMB 類型 GUID

首先這裏不作GUID與整形做爲主鍵的優劣之爭,GUID自有它優點,但GUID自己是亂序的,會對索引的維護帶來性能上的損耗,數據量越大越明顯。 git

COMB 類型 GUID 是由Jimmy Nilsson在他的「The Cost of GUIDs as Primary Keys」一文中設計出來的。 sql

基本設計思路是這樣的:既然GUID數據因毫無規律可言形成索引效率低下,影響了系統的性能,那麼能不能經過組合的方式,保留GUID的前10個字 節,用後6個字節表示GUID生成的時間(DateTime),這樣咱們將時間信息與GUID組合起來,在保留GUID的惟一性的同時增長了有序性,以此 來提升索引效率。 數據庫

在NHibernate已經有代碼實現,基於1/300秒爲單位生成的,但實際Windows操做系統時鐘更新頻率多核15ms(1/67秒),單 核10ms,是沒法精確到1/300秒的,並且在短期內生成大量CombGuid時,DateTime.Now有多是不變化的,我在測試中遇到了這種 狀況,結果生成了5萬條CombGuid記錄,其中有兩萬多條是重複的,這樣在實際生產環境中若是數據插入量很是大並且頻繁的狀況下,CombGuid排 序的優點就沒有了。 c#

針對NHibernate的代碼進行了些優化,已當前時間1/10000秒爲基礎建立CombGuid,若是當前時間基數與上次建立時相同,直接累加1,確保不產生重複的CombGuid: 數組


private static readonly DateTime _CombBaseDate = new DateTime(1900, 1, 1);
private static Int32 _LastDays; // 天數
private static Int32 _LastTenthMilliseconds; // 單位:1/10 毫秒
private static readonly Int32 _MaxTenthMilliseconds = 863999999;
 
#region - NewComb -
 
/// <summary>初始化 CombGuid 結構的新實例。</summary>
/// <returns>一個新的 CombGuid 對象。</returns>
public static CombGuid NewComb()
{
    var guidArray = Guid.NewGuid().ToByteArray();
 
    var now = DateTime.Now;
 
    // Get the days and milliseconds which will be used to build the Byte String
    var days = new TimeSpan(now.Ticks - _CombBaseDate.Ticks).Days;
    var tenthMilliseconds = (Int32)(now.TimeOfDay.TotalMilliseconds * 10D);
    var lastDays = _LastDays;
    var lastTenthMilliseconds = _LastTenthMilliseconds;
    if (days > lastDays)
    {
        Interlocked.CompareExchange(ref _LastDays, days, lastDays);
        Interlocked.CompareExchange(ref _LastTenthMilliseconds, tenthMilliseconds, lastTenthMilliseconds);
    }
    else
    {
        if (tenthMilliseconds > lastTenthMilliseconds)
        {
            Interlocked.CompareExchange(ref _LastTenthMilliseconds, tenthMilliseconds, lastTenthMilliseconds);
        }
        else
        {
            if (_LastTenthMilliseconds < Int32.MaxValue) { Interlocked.Increment(ref _LastTenthMilliseconds); }
            tenthMilliseconds = _LastTenthMilliseconds;
        }
    }
    // Convert to a Byte array
    var daysArray = BitConverter.GetBytes(days);
    var msecsArray = BitConverter.GetBytes(tenthMilliseconds);
 
    // Reverse the bytes to match SQL Servers ordering
    Array.Reverse(daysArray);
    Array.Reverse(msecsArray);
 
    // Copy the bytes into the guid
    Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
    //Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
    Array.Copy(msecsArray, 0, guidArray, guidArray.Length - 4, 4);
 
    return new CombGuid(guidArray, true);
}
 
#endregion



 這樣理論上一天以內容許生成 864000000 個不重複的CombGuid;若是當天生成的個數大於 864000000 ,會一直累加 1 直到 2147483647 ,也就是說實際一天以內能生成 2147483647 個不重複的CombGuid。 app

 完整CombGuid代碼,參考了.net fx內部guid、sqlguid的部分方法: less


/*
 * CombGuid
 *
 * 做者:海洋餅乾
 * 時間:2014-09-10 18:42:51
 * 博客:http://www.cnblogs.com/hmking/
 * 版權:版權全部 (C) Eme Development Team 2014
*/
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
 
namespace HmFramework
{
    /// <summary>COMB 類型 GUID,要存儲在數據庫中或要從數據庫中檢索的 GUID。</summary>
    /// <remarks>COMB 類型 GUID 是由Jimmy Nilsson在他的「The Cost of GUIDs as Primary Keys」一文中設計出來的。
    /// <para>基本設計思路是這樣的:既然GUID數據因毫無規律可言形成索引效率低下,影響了系統的性能,那麼能不能經過組合的方式,
    /// 保留GUID的前10個字節,用後6個字節表示GUID生成的時間(DateTime),這樣咱們將時間信息與GUID組合起來,
    /// 在保留GUID的惟一性的同時增長了有序性,以此來提升索引效率。</para>
    /// <para>也許有人會擔憂GUID減小到10字節會形成數據出現重複,其實不用擔憂,
    /// 後6字節的時間精度能夠達到 1/10000 秒,兩個COMB類型數據徹底相同的可能性是在這 1/10000 秒內生成的兩個GUID前10個字節徹底相同,這幾乎是不可能的!</para>
    /// <para>理論上一天以內容許生成 864000000 個不重複的CombGuid;若是當天生成的個數大於 864000000 ,會一直累加 1 直到 2147483647 ,
    /// 也就是說實際一天以內能生成 2147483647 個不重複的CombGuid。</para>
    /// </remarks>
    public struct CombGuid : INullable, IComparable, IComparable<CombGuid>, IEquatable<CombGuid>, IXmlSerializable
    {
        #region -- Fields --
 
        private static readonly String _NullString = "nil";
 
        private static readonly Int32 _SizeOfGuid = 16;
 
        // Comparison orders.
        private static readonly Int32[] _GuidComparisonOrders = new Int32[16] { 10, 11, 12, 13, 14, 15, 8, 9, 6, 7, 4, 5, 0, 1, 2, 3 };
 
        // Parse orders.
        private static readonly Int32[] _GuidParseOrders32 = new Int32[32]
        {
            30, 31, 28, 29, 26, 27, 24, 25,
            22, 23, 20, 21,
            18, 19, 16, 17,
            12, 13, 14, 15,
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11   
        };
        private static readonly Int32[] _GuidParseOrders36 = new Int32[36]
        {
            34, 35, 32, 33, 30, 31, 28, 29,
            27,
            25, 26, 23, 24,
            22,
            20, 21, 18, 19,
            17,
            13, 14, 15, 16,
            12,
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11   
        };
 
        // the CombGuid is null if m_value is null
        private Byte[] m_value;
 
        #endregion
 
        #region -- 屬性 --
 
        /// <summary>CombGuid 結構的只讀實例,其值空。</summary>
        public static readonly CombGuid Null = new CombGuid(true);
 
        /// <summary>獲取 CombGuid 結構的值。 此屬性爲只讀。</summary>
        public Guid Value
        {
            get
            {
                if (IsNull)
                {
                    throw new SqlNullValueException();
                }
                else
                {
                    return new Guid(m_value);
                }
            }
        }
 
        /// <summary>獲取 CombGuid 結構的日期時間屬性。
        /// <para>若是同一時間批量生成了大量的 CombGuid 時,返回的日期時間是不許確的!</para>
        /// </summary>
        public DateTime DateTime
        {
            get
            {
                if (IsNull)
                {
                    throw new SqlNullValueException();
                }
                else
                {
                    var daysArray = new Byte[4];
                    var msecsArray = new Byte[4];
 
                    // Copy the date parts of the guid to the respective Byte arrays.
                    Array.Copy(m_value, m_value.Length - 6, daysArray, 2, 2);
                    Array.Copy(m_value, m_value.Length - 4, msecsArray, 0, 4);
 
                    // Reverse the arrays to put them into the appropriate order
                    Array.Reverse(daysArray);
                    Array.Reverse(msecsArray);
 
                    // Convert the bytes to ints
                    var days = BitConverter.ToInt32(daysArray, 0);
                    var msecs = BitConverter.ToInt32(msecsArray, 0);
 
                    var date = _CombBaseDate.AddDays(days);
                    if (msecs > _MaxTenthMilliseconds) { msecs = _MaxTenthMilliseconds; }
                    msecs /= 10;
                    return date.AddMilliseconds(msecs);
                }
            }
        }
 
        #endregion
 
        #region -- 構造 --
 
        /// <summary>實例化一個空 CombGuid 結構</summary>
        private CombGuid(Boolean isNull)
        {
            m_value = null;
        }
 
        /// <summary>使用指定的字節數組初始化 CombGuid 結構的新實例。</summary>
        /// <param name="value">包含初始化 CombGuid 的值的 16 元素字節數組。</param>
        public CombGuid(Byte[] value)
            : this(value, false) { }
 
        /// <summary>使用指定的字節數組初始化 CombGuid 結構的新實例。</summary>
        /// <param name="value">包含初始化 CombGuid 的值的 16 元素字節數組。</param>
        /// <param name="isOwner">是否 CombGuid 結構直接使用</param>
        private CombGuid(Byte[] value, Boolean isOwner)
        {
            if (value == null || value.Length != _SizeOfGuid)
            {
                throw new ArgumentException("value 的長度不是 16 個字節。");
            }
            if (isOwner)
            {
                m_value = value;
            }
            else
            {
                m_value = new Byte[_SizeOfGuid];
                value.CopyTo(m_value, 0);
            }
        }
 
        /// <summary>使用指定字符串所表示的值初始化 CombGuid 結構的新實例。</summary>
        /// <param name="comb">包含下面任一格式的 CombGuid 的字符串(「d」表示忽略大小寫的十六進制數字):
        /// <para>32 個連續的數字 dddddddddddddddddddddddddddddddd </para>
        /// <para>- 或 - </para>
        /// <para>12 和 四、四、四、8 位數字的分組,各組之間有連線符,dddddddddddd-dddd-dddd-dddd-dddddddd</para>
        /// </param>
        public CombGuid(String comb)
        {
            ValidationHelper.ArgumentNullOrEmpty(comb, "comb");
 
            Int32 a; Int16 b, c; Byte[] d;
            if (new GuidParser(comb).TryParse(out a, out b, out c, out d))
            {
                m_value = new Byte[_SizeOfGuid];
                Init(a, b, c, d);
            }
            else
            {
                throw CreateFormatException(comb);
            }
        }
 
        private static Exception CreateFormatException(String s)
        {
            return new FormatException(String.Format("Invalid CombGuid format: {0}", s));
        }
 
        /// <summary>使用指定的 Guid 參數初始化 CombGuid 結構的新實例。</summary>
        /// <param name="g">一個 Guid</param>
        public CombGuid(Guid g)
        {
            m_value = g.ToByteArray();
        }
 
        /// <summary>使用指定的整數和字節數組初始化 CombGuid 類的新實例。</summary>
        /// <param name="a">CombGuid 的開頭四個字節。</param>
        /// <param name="b">CombGuid 的下兩個字節。</param>
        /// <param name="c">CombGuid 的下兩個字節。</param>
        /// <param name="d">CombGuid 的其他 8 個字節</param>
        public CombGuid(Int32 a, Int16 b, Int16 c, Byte[] d)
        {
            ValidationHelper.ArgumentNull(d, "d");
            // Check that array is not too big
            if (d.Length != 8) { throw new ArgumentException("d 的長度不是 8 個字節。"); }
 
            m_value = new Byte[_SizeOfGuid];
            Init(a, b, c, d);
        }
 
        private void Init(Int32 a, Int16 b, Int16 c, Byte[] d)
        {
            m_value[0] = (Byte)(a);
            m_value[1] = (Byte)(a >> 8);
            m_value[2] = (Byte)(a >> 16);
            m_value[3] = (Byte)(a >> 24);
            m_value[4] = (Byte)(b);
            m_value[5] = (Byte)(b >> 8);
            m_value[6] = (Byte)(c);
            m_value[7] = (Byte)(c >> 8);
            m_value[8] = d[0];
            m_value[9] = d[1];
            m_value[10] = d[2];
            m_value[11] = d[3];
            m_value[12] = d[4];
            m_value[13] = d[5];
            m_value[14] = d[6];
            m_value[15] = d[7];
        }
 
        /// <summary>使用指定的值初始化 CombGuid 結構的新實例。</summary>
        /// <param name="a">CombGuid 的開頭四個字節。</param>
        /// <param name="b">CombGuid 的下兩個字節。</param>
        /// <param name="c">CombGuid 的下兩個字節。</param>
        /// <param name="d">CombGuid 的下一個字節。</param>
        /// <param name="e">CombGuid 的下一個字節。</param>
        /// <param name="f">CombGuid 的下一個字節。</param>
        /// <param name="g">CombGuid 的下一個字節。</param>
        /// <param name="h">CombGuid 的下一個字節。</param>
        /// <param name="i">CombGuid 的下一個字節。</param>
        /// <param name="j">CombGuid 的下一個字節。</param>
        /// <param name="k">CombGuid 的下一個字節。</param>
        public CombGuid(Int32 a, Int16 b, Int16 c, Byte d, Byte e, Byte f, Byte g, Byte h, Byte i, Byte j, Byte k)
        {
            m_value = new Byte[_SizeOfGuid];
 
            m_value[0] = (Byte)(a);
            m_value[1] = (Byte)(a >> 8);
            m_value[2] = (Byte)(a >> 16);
            m_value[3] = (Byte)(a >> 24);
            m_value[4] = (Byte)(b);
            m_value[5] = (Byte)(b >> 8);
            m_value[6] = (Byte)(c);
            m_value[7] = (Byte)(c >> 8);
            m_value[8] = d;
            m_value[9] = e;
            m_value[10] = f;
            m_value[11] = g;
            m_value[12] = h;
            m_value[13] = i;
            m_value[14] = j;
            m_value[15] = k;
        }
 
        #endregion
 
        #region -- 方法 --
 
        #region - ToByteArray -
 
        /// <summary>將此 CombGuid 結構轉換爲字節數組</summary>
        /// <returns>16 元素字節數組。</returns>
        public Byte[] ToByteArray()
        {
            var ret = new Byte[_SizeOfGuid];
            m_value.CopyTo(ret, 0);
            return ret;
        }
 
        #endregion
 
        #region - GetByteArray -
 
        /// <summary>直接獲取此 CombGuid 結構內部的字節數組,若是此 CombGuid 爲空,返回空值。
        /// <para>調用此方法後,不要對獲取的字節數組作任何改變!!!</para>
        /// </summary>
        /// <returns>16 元素字節數組 或 null。</returns>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public Byte[] GetByteArray()
        {
            return m_value;
        }
 
        #endregion
 
        #region - ToString -
 
        /// <summary>已重載,將此 CombGuid 結構轉換爲字符串。</summary>
        /// <returns>返回該 CombGuid 結構的字符串表示形式。</returns>
        public override String ToString()
        {
            return ToString(CombGuidFormatStringType.Comb);
        }
 
        /// <summary>根據所提供的格式方式,返回此 CombGuid 實例值的字符串表示形式。</summary>
        /// <param name="formatType">格式化方式,它指示如何格式化此 CombGuid 的值。</param>
        /// <returns>此 CombGuid 的值,用一系列指定格式的小寫十六進制位表示</returns>
        public String ToString(CombGuidFormatStringType formatType)
        {
            if (IsNull) { return _NullString; }
 
            var offset = 0;
            var strLength = 36;
            var dash = true;
            if (formatType == CombGuidFormatStringType.Guid32Digits || formatType == CombGuidFormatStringType.Comb32Digits)
            {
                strLength = 32;
                dash = false;
            }
            var guidChars = new Char[strLength];
            var isComb = formatType == CombGuidFormatStringType.Comb || formatType == CombGuidFormatStringType.Comb32Digits;
 
            #region MS GUID類內部代碼
 
            //g[0] = (Byte)(_a);
            //g[1] = (Byte)(_a >> 8);
            //g[2] = (Byte)(_a >> 16);
            //g[3] = (Byte)(_a >> 24);
            //g[4] = (Byte)(_b);
            //g[5] = (Byte)(_b >> 8);
            //g[6] = (Byte)(_c);
            //g[7] = (Byte)(_c >> 8);
            //g[8] = _d;
            //g[9] = _e;
            //g[10] = _f;
            //g[11] = _g;
            //g[12] = _h;
            //g[13] = _i;
            //g[14] = _j;
            //g[15] = _k;
            //// [{|(]dddddddd[-]dddd[-]dddd[-]dddd[-]dddddddddddd[}|)]
            //offset = HexsToChars(guidChars, offset, _a >> 24, _a >> 16);
            //offset = HexsToChars(guidChars, offset, _a >> 8, _a);
            //if (dash) guidChars[offset++] = '-';
            //offset = HexsToChars(guidChars, offset, _b >> 8, _b);
            //if (dash) guidChars[offset++] = '-';
            //offset = HexsToChars(guidChars, offset, _c >> 8, _c);
            //if (dash) guidChars[offset++] = '-';
            //offset = HexsToChars(guidChars, offset, _d, _e);
            //if (dash) guidChars[offset++] = '-';
            //offset = HexsToChars(guidChars, offset, _f, _g);
            //offset = HexsToChars(guidChars, offset, _h, _i);
            //offset = HexsToChars(guidChars, offset, _j, _k);
 
            #endregion
 
            if (isComb)
            {
                offset = HexsToChars(guidChars, offset, m_value[10], m_value[11]);
                offset = HexsToChars(guidChars, offset, m_value[12], m_value[13]);
                offset = HexsToChars(guidChars, offset, m_value[14], m_value[15]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[8], m_value[9]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[6], m_value[7]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[4], m_value[5]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[0], m_value[1]);
                offset = HexsToChars(guidChars, offset, m_value[2], m_value[3]);
            }
            else
            {
                offset = HexsToChars(guidChars, offset, m_value[3], m_value[2]);
                offset = HexsToChars(guidChars, offset, m_value[1], m_value[0]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[5], m_value[4]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[7], m_value[6]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[8], m_value[9]);
                if (dash) { guidChars[offset++] = '-'; }
                offset = HexsToChars(guidChars, offset, m_value[10], m_value[11]);
                offset = HexsToChars(guidChars, offset, m_value[12], m_value[13]);
                offset = HexsToChars(guidChars, offset, m_value[14], m_value[15]);
            }
 
            return new String(guidChars, 0, strLength);
        }
 
        private static Int32 HexsToChars(Char[] guidChars, Int32 offset, Int32 a, Int32 b)
        {
            guidChars[offset++] = HexToChar(a >> 4);
            guidChars[offset++] = HexToChar(a);
            guidChars[offset++] = HexToChar(b >> 4);
            guidChars[offset++] = HexToChar(b);
            return offset;
        }
 
        private static Char HexToChar(Int32 a)
        {
            a = a & 0xf;
            return (Char)((a > 9) ? a - 10 + 0x61 : a + 0x30);
        }
 
        #endregion
 
        #endregion
 
        #region -- 靜態方法 --
 
        private static readonly DateTime _CombBaseDate = new DateTime(1900, 1, 1);
        private static Int32 _LastDays; // 天數
        private static Int32 _LastTenthMilliseconds; // 單位:1/10 毫秒
        private static readonly Int32 _MaxTenthMilliseconds = 863999999;
 
        #region - NewComb -
 
        /// <summary>初始化 CombGuid 結構的新實例。</summary>
        /// <returns>一個新的 CombGuid 對象。</returns>
        public static CombGuid NewComb()
        {
            var guidArray = Guid.NewGuid().ToByteArray();
 
            var now = DateTime.Now;
 
            // Get the days and milliseconds which will be used to build the Byte String
            var days = new TimeSpan(now.Ticks - _CombBaseDate.Ticks).Days;
            var tenthMilliseconds = (Int32)(now.TimeOfDay.TotalMilliseconds * 10D);
            var lastDays = _LastDays;
            var lastTenthMilliseconds = _LastTenthMilliseconds;
            if (days > lastDays)
            {
                Interlocked.CompareExchange(ref _LastDays, days, lastDays);
                Interlocked.CompareExchange(ref _LastTenthMilliseconds, tenthMilliseconds, lastTenthMilliseconds);
            }
            else
            {
                if (tenthMilliseconds > lastTenthMilliseconds)
                {
                    Interlocked.CompareExchange(ref _LastTenthMilliseconds, tenthMilliseconds, lastTenthMilliseconds);
                }
                else
                {
                    if (_LastTenthMilliseconds < Int32.MaxValue) { Interlocked.Increment(ref _LastTenthMilliseconds); }
                    tenthMilliseconds = _LastTenthMilliseconds;
                }
            }
            // Convert to a Byte array
            var daysArray = BitConverter.GetBytes(days);
            var msecsArray = BitConverter.GetBytes(tenthMilliseconds);
 
            // Reverse the bytes to match SQL Servers ordering
            Array.Reverse(daysArray);
            Array.Reverse(msecsArray);
 
            // Copy the bytes into the guid
            Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2);
            //Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4);
            Array.Copy(msecsArray, 0, guidArray, guidArray.Length - 4, 4);
 
            return new CombGuid(guidArray, true);
        }
 
        #endregion
 
        #region - Parse -
 
        /// <summary>將 CombGuid 的字符串表示形式轉換爲等效的 CombGuid 結構。</summary>
        /// <param name="s">包含下面任一格式的 CombGuid 的字符串(「d」表示忽略大小寫的十六進制數字):
        /// <para>32 個連續的數字 dddddddddddddddddddddddddddddddd </para>
        /// <para>- 或 - </para>
        /// <para>12 和 四、四、四、8 位數字的分組,各組之間有連線符,dddddddddddd-dddd-dddd-dddd-dddddddd</para>
        /// </param>
        /// <returns></returns>
        public static CombGuid Parse(String s)
        {
            if (_NullString == s)
            {
                return CombGuid.Null;
            }
            else
            {
                return new CombGuid(s);
            }
        }
 
        #endregion
 
        #region - TryParse -
 
        /// <summary>將 CombGuid 的字符串表示形式轉換爲等效的 CombGuid 結構。</summary>
        /// <param name="comb">包含下面任一格式的 CombGuid 的字符串(「d」表示忽略大小寫的十六進制數字):
        /// <para>32 個連續的數字 dddddddddddddddddddddddddddddddd </para>
        /// <para>- 或 - </para>
        /// <para>12 和 四、四、四、8 位數字的分組,各組之間有連線符,dddddddddddd-dddd-dddd-dddd-dddddddd</para>
        /// </param>
        /// <param name="result">將包含已分析的值的結構。 若是此方法返回 true,result 包含有效的 CombGuid。 若是此方法返回 false,result 等於 CombGuid.Null。</param>
        /// <returns></returns>
        public static Boolean TryParse(String comb, out CombGuid result)
        {
            ValidationHelper.ArgumentNullOrEmpty(comb, "comb");
 
            Int32 a; Int16 b, c; Byte[] d;
            if (new GuidParser(comb).TryParse(out a, out b, out c, out d))
            {
                result = new CombGuid(a, b, c, d);
                return true;
            }
            result = Null;
            return false;
        }
 
        /// <summary>將 CombGuid 的字符串表示形式轉換爲等效的 CombGuid 結構。</summary>
        /// <param name="value">Guid結構、CombGuid結構、16 元素字節數組 或 包含下面任一格式的 CombGuid 的字符串(「d」表示忽略大小寫的十六進制數字):
        /// <para>32 個連續的數字 dddddddddddddddddddddddddddddddd </para>
        /// <para>- 或 - </para>
        /// <para>12 和 四、四、四、8 位數字的分組,各組之間有連線符,dddddddddddd-dddd-dddd-dddd-dddddddd</para>
        /// </param>
        /// <param name="result">將包含已分析的值的結構。 若是此方法返回 true,result 包含有效的 CombGuid。 若是此方法返回 false,result 等於 CombGuid.Null。</param>
        /// <returns></returns>
        public static Boolean TryParse(Object value, out CombGuid result)
        {
            ValidationHelper.ArgumentNull(value, "comb");
 
            var type = value.GetType();
            if (type == typeof(String))
            {
                return TryParse(value as String, out result);
            }
            else if (type == typeof(Byte[]))
            {
                var bs = value as Byte[];
                if (bs.Length == _SizeOfGuid)
                {
                    result = new CombGuid(bs);
                    return true;
                }
            }
            else if (type == typeof(CombGuid))
            {
                result = (CombGuid)value;
                return true;
            }
            else if (type == typeof(Guid))
            {
                result = (CombGuid)value;
                return true;
            }
 
            result = Null;
            return false;
        }
 
        #endregion
 
        #endregion
 
        #region -- 類型轉換 --
 
        /// <summary>將此 Guid 結構轉換爲 CombGuid</summary>
        /// <param name="x">一個 Guid</param>
        /// <returns></returns>
        public static implicit operator CombGuid(Guid x)
        {
            return new CombGuid(x);
        }
 
        /// <summary>將此 CombGuid 結構轉換爲 Guid</summary>
        /// <param name="x">一個 CombGuid</param>
        /// <returns></returns>
        public static explicit operator Guid(CombGuid x)
        {
            return x.Value;
        }
 
        #endregion
 
        #region -- 重載運算符 --
 
        /// <summary>Comparison operators</summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private static CombGuidComparison Compare(CombGuid x, CombGuid y)
        {
            // Swap to the correct order to be compared
            for (Int32 i = 0; i < _SizeOfGuid; i++)
            {
                Byte b1, b2;
 
                b1 = x.m_value[_GuidComparisonOrders[i]];
                b2 = y.m_value[_GuidComparisonOrders[i]];
                if (b1 != b2)
                {
                    return (b1 < b2) ? CombGuidComparison.LT : CombGuidComparison.GT;
                }
            }
            return CombGuidComparison.EQ;
        }
 
        /// <summary>對兩個 CombGuid 結構執行邏輯比較,以肯定它們是否相等</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>它在兩個 CombGuid 結構相等時爲 True,在兩個實例不等時爲 False。</returns>
        public static Boolean operator ==(CombGuid x, CombGuid y)
        {
            if (x.IsNull || y.IsNull)
            {
                return (x.IsNull && y.IsNull);
            }
            else
            {
                return Compare(x, y) == CombGuidComparison.EQ;
            }
        }
 
        /// <summary>對兩個 CombGuid 結構執行邏輯比較,以肯定它們是否不相等。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>它在兩個 CombGuid 結構不等時爲 True,在兩個實例相等時爲 False。</returns>
        public static Boolean operator !=(CombGuid x, CombGuid y)
        {
            return !(x == y);
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否小於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例小於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean operator <(CombGuid x, CombGuid y)
        {
            if (x.IsNull || y.IsNull)
            {
                return (x.IsNull && !y.IsNull);
            }
            else
            {
                return Compare(x, y) == CombGuidComparison.LT;
            }
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否大於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例大於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean operator >(CombGuid x, CombGuid y)
        {
            if (x.IsNull || y.IsNull)
            {
                return (!x.IsNull && y.IsNull);
            }
            else
            {
                return Compare(x, y) == CombGuidComparison.GT;
            }
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否小於或等於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例小於或等於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean operator <=(CombGuid x, CombGuid y)
        {
            if (x.IsNull || y.IsNull)
            {
                return x.IsNull;
            }
            else
            {
                var cmp = Compare(x, y);
                return cmp == CombGuidComparison.LT || cmp == CombGuidComparison.EQ;
            }
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否大於或等於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例大於或等於第二個實例,則爲 True。 不然爲 False。</returns>
        public static Boolean operator >=(CombGuid x, CombGuid y)
        {
            if (x.IsNull || y.IsNull)
            {
                return y.IsNull;
            }
            else
            {
                var cmp = Compare(x, y);
                return cmp == CombGuidComparison.GT || cmp == CombGuidComparison.EQ;
            }
        }
 
        /// <summary>對兩個 CombGuid 結構執行邏輯比較,以肯定它們是否相等</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>它在兩個 CombGuid 結構相等時爲 True,在兩個實例不等時爲 False。</returns>
        public static Boolean Equals(CombGuid x, CombGuid y)
        {
            return (x == y);
        }
 
        /// <summary>對兩個 CombGuid 結構執行邏輯比較,以肯定它們是否不相等。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>它在兩個 CombGuid 結構不等時爲 True,在兩個實例相等時爲 False。</returns>
        public static Boolean NotEquals(CombGuid x, CombGuid y)
        {
            return (x != y);
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否小於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例小於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean LessThan(CombGuid x, CombGuid y)
        {
            return (x < y);
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否大於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例大於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean GreaterThan(CombGuid x, CombGuid y)
        {
            return (x > y);
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否小於或等於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例小於或等於第二個實例,則它爲 True。 不然爲 False。</returns>
        public static Boolean LessThanOrEqual(CombGuid x, CombGuid y)
        {
            return (x <= y);
        }
 
        /// <summary>對 CombGuid 結構的兩個實例進行比較,以肯定第一個實例是否大於或等於第二個實例。</summary>
        /// <param name="x">一個 CombGuid 結構</param>
        /// <param name="y">一個 CombGuid 結構</param>
        /// <returns>若是第一個實例大於或等於第二個實例,則爲 True。 不然爲 False。</returns>
        public static Boolean GreaterThanOrEqual(CombGuid x, CombGuid y)
        {
            return (x >= y);
        }
 
        #endregion
 
        #region -- CombGuid 相等 --
 
        /// <summary>已重載,判斷兩個 CombGuid 結構是否相等</summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public override Boolean Equals(Object value)
        {
            if ((value.GetType() != typeof(CombGuid))) { return false; }
 
            return this == (CombGuid)value;
        }
 
        /// <summary>判斷兩個 CombGuid 結構是否相等</summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public Boolean Equals(CombGuid value)
        {
            return this == value;
        }
 
        /// <summary>已重載,獲取該 CombGuid 結構的哈希代碼</summary>
        /// <returns></returns>
        public override Int32 GetHashCode()
        {
            return IsNull ? 0 : Value.GetHashCode();
        }
 
        #endregion
 
        #region -- INullable 成員 --
 
        /// <summary>獲取一個布爾值,該值指示此 CombGuid 結構是否爲 null。</summary>
        public Boolean IsNull
        {
            get { return (m_value == null); }
        }
 
        #endregion
 
        #region -- IComparable 成員 --
 
        /// <summary>將此 CombGuid 結構與所提供的對象進行比較,並返回其相對值的指示。 不單單是比較最後 6 個字節,但會將最後 6 個字節視爲比較中最重要的字節。</summary>
        /// <param name="value">要比較的對象</param>
        /// <returns>一個有符號的數字,它指示該實例和對象的相對值。
        /// <para>小於零,此實例小於對象。</para>
        /// <para>零,此實例等於對象。</para>
        /// <para>大於零,此實例大於對象;或對象是 null 引用 (Nothing)</para>
        /// </returns>
        public Int32 CompareTo(Object value)
        {
            if (value.GetType() == typeof(CombGuid))
            {
                var combGuid = (CombGuid)value;
 
                return CompareTo(combGuid);
            }
            throw new ArgumentException("value 類型不是 CombGuid");
        }
 
        /// <summary>將此 CombGuid 結構與所提供的 CombGuid 結構進行比較,並返回其相對值的指示。 不單單是比較最後 6 個字節,但會將最後 6 個字節視爲比較中最重要的字節。</summary>
        /// <param name="value">要比較的 CombGuid 結構</param>
        /// <returns>一個有符號的數字,它指示該實例和對象的相對值。
        /// <para>小於零,此實例小於對象。</para>
        /// <para>零,此實例等於對象。</para>
        /// <para>大於零,此實例大於對象;或對象是 null 引用 (Nothing)</para>
        /// </returns>
        public Int32 CompareTo(CombGuid value)
        {
            // If both Null, consider them equal.
            // Otherwise, Null is less than anything.
            if (IsNull)
            {
                return value.IsNull ? 0 : -1;
            }
            else if (value.IsNull)
            {
                return 1;
            }
 
            //if (this < value) { return -1; }
            //if (this > value) { return 1; }
            //return 0;
            var cmp = Compare(this, value);
            switch (cmp)
            {
                case CombGuidComparison.LT:
                    return -1;
 
                case CombGuidComparison.GT:
                    return 1;
 
                case CombGuidComparison.EQ:
                default:
                    return 0;
            }
        }
 
        #endregion
 
        #region -- IXmlSerializable 成員 --
 
        XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }
 
        /// <summary>從 CombGuid 結構的 XML 表示形式生成該對象</summary>
        /// <param name="reader"></param>
        void IXmlSerializable.ReadXml(XmlReader reader)
        {
            var isNull = reader.GetAttribute(_NullString, XmlSchema.InstanceNamespace);
            if (isNull != null && XmlConvert.ToBoolean(isNull))
            {
                // VSTFDevDiv# 479603 - SqlTypes read null value infinitely and never read the next value. Fix - Read the next value.
                reader.ReadElementString();
                m_value = null;
            }
            else
            {
                m_value = new Guid(reader.ReadElementString()).ToByteArray();
            }
        }
 
        /// <summary>將該 CombGuid 結構轉換爲其 XML 表示形式</summary>
        /// <param name="writer"></param>
        void IXmlSerializable.WriteXml(XmlWriter writer)
        {
            if (IsNull)
            {
                writer.WriteAttributeString("xsi", _NullString, XmlSchema.InstanceNamespace, "true");
            }
            else
            {
                writer.WriteString(XmlConvert.ToString(new Guid(m_value)));
            }
        }
 
        public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet)
        {
            return new XmlQualifiedName("String", XmlSchema.Namespace);
        }
 
        #endregion
 
        #region -- struct GuidParser --
 
        private struct GuidParser
        {
            private String _src;
            private Int32 _length;
            private Int32 _cur;
 
            internal GuidParser(String src)
            {
                _src = src.Trim();
                _cur = 0;
                _length = _src.Length;
            }
 
            private void Reset()
            {
                _cur = 0;
                _length = _src.Length;
            }
 
            private Boolean Eof
            {
                get { return _cur >= _length; }
            }
 
            internal Boolean TryParse(out Int32 a, out Int16 b, out Int16 c, out Byte[] d)
            {
                var hasHyphen = _length == 36;
 
                a = 0; b = 0; c = 0; d = null;
                UInt64 _a, _b, _c;
 
                if (!ParseHex(8, hasHyphen, out _a)) { return false; }
 
                if (hasHyphen && !ParseChar('-')) { return false; }
 
                if (!ParseHex(4, hasHyphen, out _b)) { return false; }
 
                if (hasHyphen && !ParseChar('-')) { return false; }
 
                if (!ParseHex(4, hasHyphen, out _c)) { return false; }
 
                if (hasHyphen && !ParseChar('-')) { return false; }
 
                var _d = new Byte[8];
                for (Int32 i = 0; i < _d.Length; i++)
                {
                    UInt64 dd;
                    if (!ParseHex(2, hasHyphen, out dd)) { return false; }
 
                    if (i == 1 && hasHyphen && !ParseChar('-')) { return false; }
 
                    _d[i] = (Byte)dd;
                }
 
                if (!Eof) { return false; }
 
                a = (Int32)_a;
                b = (Int16)_b;
                c = (Int16)_c;
                d = _d;
                return true;
            }
 
            private Boolean ParseChar(Char c)
            {
                if (!Eof && _src[_GuidParseOrders36[_cur]] == c)
                {
                    _cur++;
                    return true;
                }
 
                return false;
            }
 
            private Boolean ParseHex(Int32 length, Boolean hasHyphen, out UInt64 res) //Boolean strict
            {
                res = 0;
 
                for (Int32 i = 0; i < length; i++)
                {
                    //if (Eof)
                    //  return !(strict && (i + 1 != length));
                    if (Eof) { return !((i + 1 != length)); }
 
                    var c = hasHyphen ? _src[_GuidParseOrders36[_cur]] : _src[_GuidParseOrders32[_cur]];
                    if (Char.IsDigit(c))
                    {
                        res = res * 16 + c - '0';
                        _cur++;
                        continue;
                    }
 
                    if (c >= 'a' && c <= 'f')
                    {
                        res = res * 16 + c - 'a' + 10;
                        _cur++;
                        continue;
                    }
 
                    if (c >= 'A' && c <= 'F')
                    {
                        res = res * 16 + c - 'A' + 10;
                        _cur++;
                        continue;
                    }
 
                    //if (!strict)
                    //  return true;
 
                    return false; //!(strict && (i + 1 != length));
                }
 
                return true;
            }
        }
 
        #endregion
 
        #region -- enum CombGuidComparison --
 
        private enum CombGuidComparison
        {
            LT,
            EQ,
            GT
        }
 
        #endregion
    }
 
    /// <summary>CombGuid 結構格式化字符串方式</summary>
    public enum CombGuidFormatStringType
    {
        /// <summary>Guid 格式字符串,用一系列指定格式的小寫十六進制位表示,由連字符("-")分隔的 32 位數字,這些十六進制位分別以 8 個、4 個、4 個、4 個和 12 個位爲一組並由連字符分隔開。</summary>
        Guid,
 
        /// <summary>Guid 格式字符串,用一系列指定格式的小寫十六進制位表示,32 位數字,這些十六進制位分別以 8 個、4 個、4 個、4 個和 12 個位爲一組合並而成。</summary>
        Guid32Digits,
 
        /// <summary>CombGuid 格式字符串,用一系列指定格式的小寫十六進制位表示,由連字符("-")分隔的 32 位數字,這些十六進制位分別以 12 個和 4 個、4 個、4 個、8 個位爲一組並由連字符分隔開。</summary>
        Comb,
 
        /// <summary>CombGuid 格式字符串,用一系列指定格式的小寫十六進制位表示,32 位數字,這些十六進制位分別以 12 個和 4 個、4 個、4 個、8 個位爲一組合並而成。</summary>
        Comb32Digits
    }
}
相關文章
相關標籤/搜索