C# 2进制、8进制、10进制、16进制...各种进制间的转换(三) 数值运算和位运算 C# 2进制、8进制、10进制、16进制...各种进制间的转换(二)搜集的各种转换及方法 C# 2进制、8进制、10进制、16进制...各种进制间的转换(一) convert 类中的方法 C#.NET 中的定时器及使用方法 依赖注入 加密 解密

C# 2进制、8进制、10进制、16进制...各种进制间的转换(三) 数值运算和位运算

 

一、数值运算

 


 

各进制的数值计算很简单,把各进制数转换成 十进制数进行计算,然后再转换成原类型即可。

举例 :二进制之间的加法

复制代码
       /// <summary>
       /// 二进制之间的加法
       /// </summary>
       /// <param name="x"></param>
       /// <param name="y"></param>
       /// <returns></returns>
       public string AddBetweenBinary(string x, string y)
       {
           int intSum = Convert.ToInt32(x, 2) + Convert.ToInt32(y, 2);
           return Convert.ToString(intSum,2) ;
       }
复制代码

 

二、位运算

 


 

 什么是位运算?程序中的所有内容在计算机内存中都是以二进制的形式储存的(即:0或1),位运算就是直接对在内存中的二进制数的每位进行运算操作

在C#中可以对整型运算对象按位进行逻辑运算。按位进行逻辑运算的意义是:依次取被运算对象的每个位,进行逻辑运算,每个位的逻辑运算结果是结果值的每个位。

C#支持的位逻辑运算符如表所示。

 

1、位逻辑非运算 
位逻辑非运算是单目的,只有一个运算对象。位逻辑非运算按位对运算对象的值进行非运算,即:如果某一位等于0,就将其转变为1;如果某一位等于1,就将其转变为0。

比如,对二进制的10010001进行位逻辑非运算,结果等于01101110,用十进制表示就是:~145等于110;

对二进制的01010101进行位逻辑非运算,结果等于10101010。用十进制表示就是~85等于176。 


2、位逻辑与运算 
位逻辑与运算将两个运算对象按位进行与运算。与运算的规则:1与1等于1,1与0等于0。 
比如:10010001(二进制)&11110000等于10010000(二进制)。 


3、位逻辑或运算 
位逻辑或运算将两个运算对象按位进行或运算。或运算的规则是:1或1等1,1或0等于1, 0或0等于0。

比如10010001(二进制)| 11110000(二进制)等于11110001(二进制)。

 
4、位逻辑异或运算 
位逻辑异或运算将两个运算对象按位进行异或运算。异或运算的规则是:1异或1等于0,1异或0等于1,0异或0等于0。即:相同得0,相异得1。  

比如:10010001(二进制)^11110000(二进制)等于01100001(二进制)。 


5、位左移运算 
位左移运算将整个数按位左移若干位,左移后空出的部分0。

比如:8位的byte型变量 byte a=0x65(即二进制的01100101),将其左移3位:a<<3的结果是0x27(即二进制的00101000)。 

6、位右移运算 
位右移运算将整个数按位右移若干位,右移后空出的部分填0。

比如:8位的byte型变量 Byte a=0x65(既(二进制的01100101))将其右移3位:a>>3的结果是0x0c(二进制00001100)。
 
在进行位与、或、异或运算时,如果两个运算对象的类型一致,则运算结果的类型就是运算对象的类型。比如对两个int变量a和b做与运算,运算结果的类型还是int型。如果两个运算对象的类型不一致,则C#要对不一致的类型进行类型转换,变成一致的类型,然后进行运算。

 

 

C# 2进制、8进制、10进制、16进制...各种进制间的转换(二)搜集的各种转换及方法

 

复制代码
/// <summary>
        /// 十进制转换为二进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string DecToBin(string x)
        {
            string z = null;
            int X = Convert.ToInt32(x);
            int i = 0;
            long a, b = 0;
            while (X > 0)
            {
                a = X%2;
                X = X/2;
                b = b + a*Pow(10, i);
                i++;
            }
            z = Convert.ToString(b);
            return z;
        }

        /// <summary>
        /// 16进制转ASCII码
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static string HexToAscii(string hexString)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i <= hexString.Length - 2; i += 2)
            {
                sb.Append(
                    Convert.ToString(
                        Convert.ToChar(Int32.Parse(hexString.Substring(i, 2),
                                                   System.Globalization.NumberStyles.HexNumber))));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 十进制转换为八进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string DecToOtc(string x)
        {
            string z = null;
            int X = Convert.ToInt32(x);
            int i = 0;
            long a, b = 0;
            while (X > 0)
            {
                a = X%8;
                X = X/8;
                b = b + a*Pow(10, i);
                i++;
            }
            z = Convert.ToString(b);
            return z;
        }

        /// <summary>
        /// 十进制转换为十六进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string DecToHex(string x)
        {
            if (string.IsNullOrEmpty(x))
            {
                return "0";
            }
            string z = null;
            int X = Convert.ToInt32(x);
            Stack a = new Stack();
            int i = 0;
            while (X > 0)
            {
                a.Push(Convert.ToString(X%16));
                X = X/16;
                i++;
            }
            while (a.Count != 0)
                z += ToHex(Convert.ToString(a.Pop()));
            if (string.IsNullOrEmpty(z))
            {
                z = "0";
            }
            return z;
        }

        /// <summary>
        /// 二进制转换为十进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string BinToDec(string x)
        {
            string z = null;
            int X = Convert.ToInt32(x);
            int i = 0;
            long a, b = 0;
            while (X > 0)
            {
                a = X%10;
                X = X/10;
                b = b + a*Pow(2, i);
                i++;
            }
            z = Convert.ToString(b);
            return z;
        }

        /// <summary>
        /// 二进制转换为十进制,定长转换
        /// </summary>
        /// <param name="x"></param>
        /// <param name="iLength"></param>
        /// <returns></returns>
        public static string BinToDec(string x, short iLength)
        {
            StringBuilder sb = new StringBuilder();
            int iCount = 0;

            iCount = x.Length/iLength;

            if (x.Length%iLength > 0)
            {
                iCount += 1;
            }

            int X = 0;

            for (int i = 0; i < iCount; i++)
            {
                if ((i + 1)*iLength > x.Length)
                {
                    X = Convert.ToInt32(x.Substring(i*iLength, (x.Length - iLength)));
                }
                else
                {
                    X = Convert.ToInt32(x.Substring(i*iLength, iLength));
                }
                int j = 0;
                long a, b = 0;
                while (X > 0)
                {
                    a = X%10;
                    X = X/10;
                    b = b + a*Pow(2, j);
                    j++;
                }
                sb.AppendFormat("{0:D2}", b);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 二进制转换为十六进制,定长转换
        /// </summary>
        /// <param name="x"></param>
        /// <param name="iLength"></param>
        /// <returns></returns>
        public static string BinToHex(string x, short iLength)
        {
            StringBuilder sb = new StringBuilder();
            int iCount = 0;

            iCount = x.Length/iLength;

            if (x.Length%iLength > 0)
            {
                iCount += 1;
            }

            int X = 0;

            for (int i = 0; i < iCount; i++)
            {
                if ((i + 1)*iLength > x.Length)
                {
                    X = Convert.ToInt32(x.Substring(i*iLength, (x.Length - iLength)));
                }
                else
                {
                    X = Convert.ToInt32(x.Substring(i*iLength, iLength));
                }
                int j = 0;
                long a, b = 0;
                while (X > 0)
                {
                    a = X%10;
                    X = X/10;
                    b = b + a*Pow(2, j);
                    j++;
                }
                //前补0
                sb.Append(DecToHex(b.ToString()));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 八进制转换为十进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string OctToDec(string x)
        {
            string z = null;
            int X = Convert.ToInt32(x);
            int i = 0;
            long a, b = 0;
            while (X > 0)
            {
                a = X%10;
                X = X/10;
                b = b + a*Pow(8, i);
                i++;
            }
            z = Convert.ToString(b);
            return z;
        }


        /// <summary>
        /// 十六进制转换为十进制
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string HexToDec(string x)
        {
            if (string.IsNullOrEmpty(x))
            {
                return "0";
            }
            string z = null;
            Stack a = new Stack();
            int i = 0, j = 0, l = x.Length;
            long Tong = 0;
            while (i < l)
            {
                a.Push(ToDec(Convert.ToString(x[i])));
                i++;
            }
            while (a.Count != 0)
            {
                Tong = Tong + Convert.ToInt64(a.Pop())*Pow(16, j);
                j++;
            }
            z = Convert.ToString(Tong);
            return z;
        }

        #endregion //Helperfunctions

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private static long Pow(long x, long y)
        {
            int i = 1;
            long X = x;
            if (y == 0)
                return 1;
            while (i < y)
            {
                x = x*X;
                i++;
            }
            return x;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        private static string ToDec(string x)
        {
            switch (x)
            {
                case "A":
                    return "10";
                case "B":
                    return "11";
                case "C":
                    return "12";
                case "D":
                    return "13";
                case "E":
                    return "14";
                case "F":
                    return "15";
                default:
                    return x;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        private static string ToHex(string x)
        {
            switch (x)
            {
                case "10":
                    return "A";
                case "11":
                    return "B";
                case "12":
                    return "C";
                case "13":
                    return "D";
                case "14":
                    return "E";
                case "15":
                    return "F";
                default:
                    return x;
            }
        }

        /// <summary>
        /// 将16进制BYTE数组转换成16进制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToHexString(byte[] bytes) // 0xae00cf => "AE00CF "
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();

                for (int i = 0; i < bytes.Length; i++)
                {
                    strB.Append(bytes[i].ToString("X2"));
                }
                hexString = strB.ToString();
            }
            return hexString;
        }
复制代码

 

复制代码
/// <summary>
        /// 
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="iLength"></param>
        /// <returns></returns>
        public static string ToHexString(byte[] bytes, int iLength) // 0xae00cf => "AE00CF "
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();

                if (bytes.Length < iLength)
                {
                    iLength = bytes.Length;
                }

                for (int i = 0; i < iLength; i++)
                {
                    strB.Append(bytes[i].ToString("X2"));
                }
                hexString = strB.ToString();
            }
            return hexString;
        }

        /// <summary>
        /// 将byte数组转换为16进制字符串
        /// </summary>
        /// <param name="bytes">要转换的数组</param>
        /// <param name="iStart">数组下标</param>
        /// <param name="iLength">长度</param>
        /// <returns></returns>
        public static string ToHexString(byte[] bytes, int iStart, int iLength) // 0xae00cf => "AE00CF "
        {
            string hexString = string.Empty;
            if (bytes != null)
            {
                StringBuilder strB = new StringBuilder();

                //缓冲区长度问题,需清空缓冲区
                if (bytes.Length < (iLength + iStart))
                {
                    iLength = bytes.Length;
                }

                for (int i = iStart; i < iLength + iStart; i++)
                {
                    strB.Append(bytes[i].ToString("X2"));
                }
                hexString = strB.ToString();
            }
            return hexString;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <param name="discarded"></param>
        /// <returns></returns>
        public static byte[] GetBytes(string hexString, out int discarded)
        {
            discarded = 0;
            string newString = "";
            char c;
            // remove all none A-F, 0-9, characters
            for (int i = 0; i < hexString.Length; i++)
            {
                c = hexString[i];
                if (Uri.IsHexDigit(c))
                    newString += c;
                else
                    discarded++;
            }
            // if odd number of characters, discard last character
            if (newString.Length%2 != 0)
            {
                discarded++;
                newString = newString.Substring(0, newString.Length - 1);
            }

            return HexToByte(newString);
        }

        /// <summary>
        /// Converts from binary coded decimal to integer
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static uint BcdToDec(uint num)
        {
            return HornerScheme(num, 0x10, 10);
        }

        /// <summary>
        /// Converts from integer to binary coded decimal
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static uint DecToBcd(uint num)
        {
            return HornerScheme(num, 10, 0x10);
        }

        private static uint HornerScheme(uint num, uint divider, uint factor)
        {
            uint remainder = 0, quotient = 0, result = 0;
            remainder = num%divider;
            quotient = num/divider;
            if (!(quotient == 0 && remainder == 0))
                result += HornerScheme(quotient, divider, factor)*factor + remainder;
            return result;
        }

        /// <summary>
        /// byte数组尾部0截取函数
        /// </summary>
        /// <param name="buf">原始byte数组</param>
        /// <param name="iLength">要截取的长度</param>
        /// <returns>截取后的数组</returns>
        public static byte[] InterceptByte(byte[] buf, int iLength)
        {
            StringBuilder sb = new StringBuilder(iLength*2);
            sb = sb.Append(ToHexString(buf, (short) iLength));
            int discarded = 0;
            byte[] bReturn = GetBytes(sb.ToString(), out discarded);

            if (discarded > 0)
            {
                throw new Exception("byte数组截取有数据丢失!");
            }
            return bReturn;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        public static byte[] HexToByte(string hexString)
        {
            if (string.IsNullOrEmpty(hexString))
            {
                hexString = "00";
            }
            byte[] returnBytes = new byte[hexString.Length/2];
            for (int i = 0; i < returnBytes.Length; i++)
                returnBytes[i] = Convert.ToByte(hexString.Substring(i*2, 2), 16);
            return returnBytes;
        }

        /// <summary>
        /// 日期转BCD数组
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="type">4 6 7</param>
        /// <returns></returns>
        public static byte[] DateTimeToBCD(DateTime dateTime, ushort type)
        {
            string strServerTime = string.Format("{0:yyyyMMddHHmmss}", dateTime);

            byte[] bcd = new byte[type];
            if (type == 4)
            {
                bcd[0] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(0, 2))).ToString("D2"));
                bcd[1] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(2, 2))).ToString("D2"));
                bcd[2] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(4, 2))).ToString("D2"));
                bcd[3] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(6, 2))).ToString("D2"));
            }
            if (type == 6)
            {
                bcd[0] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(2, 2))).ToString("D2"));
                bcd[1] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(4, 2))).ToString("D2"));
                bcd[2] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(6, 2))).ToString("D2"));
                bcd[3] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(8, 2))).ToString("D2"));
                bcd[4] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(10, 2))).ToString("D2"));
                bcd[5] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(12, 2))).ToString("D2"));
            }
            if (type == 7)
            {
                bcd[0] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(0, 2))).ToString("D2"));
                bcd[1] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(2, 2))).ToString("D2"));
                bcd[2] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(4, 2))).ToString("D2"));
                bcd[3] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(6, 2))).ToString("D2"));
                bcd[4] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(8, 2))).ToString("D2"));
                bcd[5] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(10, 2))).ToString("D2"));
                bcd[5] = byte.Parse(DecToBcd(uint.Parse(strServerTime.Substring(12, 2))).ToString("D2"));
            }
            return bcd;
        }

        /// <summary>
        /// BCD时间转日期时间
        /// </summary>
        /// <param name="bcdTime"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static DateTime BCDToDateTime(byte[] bcdTime, ushort type)
        {
            StringBuilder sb = new StringBuilder();
            if (type == 4) //4位BCD码的日期
            {
                sb.Append(BcdToDec(bcdTime[0]).ToString("D2"));
                sb.Append(BcdToDec(bcdTime[1]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[2]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[3]).ToString("D2") + " ");
            }
            if (type == 6) //6位BCD码的时间
            {
                sb.Append(DateTime.Now.ToString("yyyy").Substring(0, 2));
                sb.Append(BcdToDec(bcdTime[0]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[1]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[2]).ToString("D2") + " ");
                sb.Append(BcdToDec(bcdTime[3]).ToString("D2") + ":");
                sb.Append(BcdToDec(bcdTime[4]).ToString("D2") + ":");
                sb.Append(BcdToDec(bcdTime[5]));
            }
            if (type == 7) //7位BCD码的日期
            {
                sb.Append(BcdToDec(bcdTime[0]).ToString("D2"));
                sb.Append(BcdToDec(bcdTime[1]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[2]).ToString("D2"));
                sb.Append('-' + BcdToDec(bcdTime[3]).ToString("D2") + " ");
                sb.Append(BcdToDec(bcdTime[4]).ToString("D2") + ":");
                sb.Append(BcdToDec(bcdTime[5]).ToString("D2") + ":");
                sb.Append(BcdToDec(bcdTime[6]));
            }

            DateTime dt;
            //2011-3-26 当日期出错时的处理
            DateTime.TryParse(sb.ToString(), out dt);

            return dt;
        }
    }
}
复制代码

 

C# 2进制、8进制、10进制、16进制...各种进制间的转换(一) convert 类中的方法

 

  常见的进制方式,主要有二进制,八进制,十进制和十六进制,通用的转换方式是把非十进制的数据类型转换成十进制的,然后再转换成其他类型。

   在.NET Framework中,System.Convert 类中提供了较为全面的各种类型、数值之间的转换功能。其中的两个方法可以轻松的实现各种进制的数值间的转换

 

一 、Convert 类中的转换方法

 


 

1、Convert.ToInt32(string value, int fromBase); 
  把不同进制数值的字符串转换为数字(十进制)

                       value 参数 要进行转换的数值字符串

                       fromBase参数 要转换成的进制格式,只能是2、8、10及16。 

Convert.ToInt32(”100111101″, 2); //二进制数 100111101 转成十进制

Convert.ToInt32(”76″, 8);        //八进数 76 制转成十进制

Convert.ToInt32(”FF”, 16);       // 16进数 FF 制转换成十进制

 


2、Convert.ToString(int value, int toBase);
  可以把一个数字(十进制)转换为不同进制数值的字符串格式,

       value 参数 要进行转换的数字(十进制数)

                       toBase参数 要转换成的进制格式,只能是2、8、10及16。

 

Convert.ToString(69, 2); //十进制数 69 转二进制

Convert.ToString(69, 8); //十进制数 69 转八进制

Convert.ToString(69, 16);//十进制数 69 转十六进制

 

 

 二 、一个各进制自由转换的方法

 


 

进制转换的入口函数:

复制代码
       /// <summary>
       /// 进制转换
       /// </summary>
       /// <param name="input"></param>
       /// <param name="fromType">原来的进制格式</param>
       /// <param name="toType">要转换成的进制格式</param>
       /// <returns></returns>
       public string ConvertGenericBinary(string input, byte fromType, byte toType)
       {
           string output = input;
           switch (fromType)
           { 
               case 2:
                   output = ConvertGenericBinaryFromBinary(input,toType);
                   break;
               case 8:
                   output = ConvertGenericBinaryFromOctal(input,toType);
                   break;
               case 10:
                   output = ConvertGenericBinaryFromDecimal(input,toType);
                   break ;
               case 16:
                   output = ConvertGenericBinaryFromHexadecimal(input,toType);
                   break;
               default:
                   break;
           }
           return output;
       }     
复制代码

 

从二进制转换到其他格式:

复制代码
       /// <summary>
       /// 从二进制转换成其他进制
       /// </summary>
       /// <param name="input"></param>
       /// <param name="toType"></param>
       /// <returns></returns>
       private string ConvertGenericBinaryFromBinary(string input,  byte toType)
       {           
           switch (toType)
           { 
               case 8:
                   //先转换成十进制然后转八进制
                   input = Convert.ToString(Convert.ToInt32(input, 2), 8);
                   break;
               case 10:
                   input =  Convert.ToInt32(input, 2).ToString();
                   break;
               case 16:
                   input = Convert.ToString(Convert.ToInt32(input, 2), 16);
                   break;
               default:
                   break; 
           }
           return input;
       }
复制代码

 

从八进制转换成其他格式:

复制代码
       /// <summary>
       /// 从八进制转换成其他进制
       /// </summary>
       /// <param name="input"></param>
       /// <param name="toType"></param>
       /// <returns></returns>
       private string ConvertGenericBinaryFromOctal(string input, byte toType)
       {
           switch (toType)
           {
               case 2:
                   input =  Convert.ToString(Convert.ToInt32(input, 8), 2);
                   break;
               case 10:
                   input = Convert.ToInt32(input, 8).ToString();
                   break;
               case 16:
                   input = Convert.ToString(Convert.ToInt32(input, 8), 16);
                   break;
               default:
                   break;
           }
           return input;
       }
复制代码

 

从十进制转换到其他格式:

复制代码
       /// <summary>
       /// 从十进制转换成其他进制
       /// </summary>
       /// <param name="input"></param>
       /// <param name="toType"></param>
       /// <returns></returns>
       private string ConvertGenericBinaryFromDecimal(string input, int toType)
       {
           string output = "";
           int intInput = Convert.ToInt32(input);
           switch (toType)
           {
               case 2:
                   output = Convert.ToString(intInput, 2);
                   break;
               case 8:
                   output = Convert.ToString(intInput, 8);
                   break;
               case 16:
                   output = Convert.ToString(intInput, 16);
                   break;
               default:
                   output = input;
                   break;
           }
           return output;
       }
复制代码

 

从十六进制转换到其他格式:

复制代码
       /// <summary>
       /// 从十六进制转换成其他进制
       /// </summary>
       /// <param name="input"></param>
       /// <param name="toType"></param>
       /// <returns></returns>
       private string ConvertGenericBinaryFromHexadecimal(string input, int toType)
       {
           switch (toType)
           {
               case 2:
                   input = Convert.ToString(Convert.ToInt32(input, 16), 2);
                   break;
               case 8:
                   input = Convert.ToString(Convert.ToInt32(input, 16), 8);
                   break;
               case 10:
                   input = Convert.ToInt32(input, 16).ToString();
                   break;
               default:
                   break;
           }
           return input;
       }
复制代码

 

 

 三、各进制数的运算

 


 

  把各进制数转换成 十进制数进行计算,然后再转换成原类型。

举例一个二进制之间的加法:

复制代码
       /// <summary>
       /// 二进制之间的加法
       /// </summary>
       /// <param name="x"></param>
       /// <param name="y"></param>
       /// <returns></returns>
       public string AddBetweenBinary(string x, string y)
       {
           int intSum = Convert.ToInt32(x, 2) + Convert.ToInt32(y, 2);
           return Convert.ToString(intSum,2) ;
       }
复制代码

 

C#.NET 中的定时器及使用方法

 

定时器是系统常用的组件之一,程序员可以根据自己的需求定制一个定时器类型,也可以使用.net内建的定时器类型。在.net中一共为程序员提供了3种定时器:

  • System.Windows.Forms.Timer类型
  • System.Threading.Timer类型
  • System.Timers.Timer类型

 

一、System.Windows.Forms.Timer

  从这个定时器的命名空间可以看出,.net设计这个定时器的目的是为了方便程序员在Window Form中使用的定时器。当一个System.Windows.Forms.Timer类被构造时,当前定时器会和当前线程进行关联。而当计时器的计满后,一个定时器消息将被插入到当前线程的消息队列中。当前线程逐一处理消息中的所有消息,并一一派发给各自的处理方法。这样的机制和利用工作者进程定时有很大的区别,

  System.Windows.Forms.Timer类型并没有涉及多线程的操作,定时器的设置、定时方法的执行都在同一个线程之上。这就意味着System.Windows.Forms.Timer并不能准确计时,尤其当消息阻塞时,定时器的误差将会更大,因为定时器消息只能等待在前面的所有消息处理完后才能得到处理。但是因为System.Windows.Forms.Timer类型的定时器并不涉及多线程的操作,因此是线程安全的,不会发生回调方法重入的问题。

 

主要使用步骤如下:

1.       System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();//实例化 

2.      myTimer.Tick += new EventHandler(函数名); //给timer挂起事件

3.      myTimer.Enabled = true;//使timer可用

4.       myTimer.Interval = n; //设置时间间隔,以毫秒为单位

5.       myTimer.Stop(); //如果要暂停计时则使用Stop()方法

6.       myTimer.Enabled = false;//若要停止使用timer,则使之不可用

 

System.Windows.Forms.Timer例程:

复制代码
using System.Windows.Forms;
 
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        //实例化一个timer
        System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
        
    private void StartTimeBtn_Click(object sender, EventArgs e)//开始计时
        { 
            //给timer挂起事件
            myTimer.Tick  += new EventHandler(Callback);
            //使timer可用
            myTimer.Enabled = true;
            //设置时间间隔,以毫秒为单位
            myTimer.Interval = 1000;//1s
        }
        private void StopTimeBtn_Click(object sender, EventArgs e)//停止计时
        {
            //计时开始
            myTimer.Stop();
        }
        //回调函数
        private void Callback(object sender, EventArgs e)
        { 
            //获取系统时间 20:16:16
            textBox1.Text = DateTime.Now.ToLongTimeString().ToString();
        }
    }
}
复制代码

 

 

二、System.Threading.Timer

  这个定时器类的使用相对复杂,但同时它也是最优化的非常常用的一个定时器类型。System.Threading.Timer的定时方法在独立的线程上执行,定时时间更为准确。使用回调方法的计时器,而且由线程池线程服务,简单且对资源要求不高。所有的对象有一个线程控制,当下一个定时到达时,该线程会负责在线程中获得一个新的工作者线程,用以执行相应的回调方法。

  虽然这个定时器是相对最优化的一个定时器类型,但是从其机制上来讲,其并不是线程安全的,可能会出现回调方法重入的问题。解释下方法重入,是一个有关多线程编程的概念,意思大概是:同一程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据发生同步错误的bug。

 

 

 主要使用步骤如下:

1、实例构造一个线程定时器。

     System.Threading.Timer  mytimer =  

 new System.Threading.Timer(new  System.Threading.TimerCallback(timerCall), null, 0, 1000);

★timer构造函数资料:

复制代码
public Timer(
    TimerCallback callback,   // TimerCallback 委托,表示要执行的方法。
object state,    //一个包含回调方法要使用的信息的对象,或者为 null。
int dueTime, //第一次执行调用方法等待时间 // 指定零 (0) 可立即启动计时器。 //指定零 (-1) 表示本定时器被禁用。 //Change(Int32,Int32)方法可以改写定时器参数
int period // 执行间隔时间
          //如果 period 为零 (0) 或 -1 毫秒,而且dueTime 为正,则只会调用一次方法; //然后计时器的定时行为将被禁用,使用 Change 可以改写定时器参数。 )
复制代码

 

2、编写timerCall回调函数

     格式:private  void  timerCall(object   xxxxx)  { .......; .......;}

3、使用Change(Int32,Int32)方法来修改定时器参数实现停止、重新开始等。

4、使用Dispose()方法释放定时器资源。

 

System.Threading.Timer例程:

复制代码
 public startTimer()
    {
      //定义一个对象
      System.Threading.Timer timer = new System.Threading.Timer(
        new System.Threading.TimerCallback(Say), null,
        0, 1000);//1S定时器
    }
    
    //函数形式参数必须是object格式
    public void Say(object a )
    {
      Console.WriteLine("你好");
    }
复制代码

 

复制代码
using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        //创建一个事件来指示超时计数阈值 
        //定时器回调。
        AutoResetEvent autoEvent = new AutoResetEvent(false);
        StatusChecker  statusChecker = new StatusChecker(10);

        // 创建一个推断的委托,调用计时器的方法。
        TimerCallback tcb = statusChecker.CheckStatus;

        // 创建一个指示委托调用的计时器。
        Console.WriteLine("{0} Creating timer.\n",DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = new Timer(tcb, autoEvent, 1000, 250);

        // 当自动事件信号,改变周期到每一个 
        autoEvent.WaitOne(5000, false);
     stateTimer.Change(0, 500); Console.WriteLine("\nChanging period.\n"); //当autoevent信号的第二次,处置 autoEvent.WaitOne(5000, false); stateTimer.Dispose(); Console.WriteLine("\nDestroying timer."); } } class StatusChecker { private int invokeCount; private int maxCount; public StatusChecker(int count) { invokeCount = 0; maxCount = count; } // 此方法由定时器委托调用。 public void CheckStatus(Object stateInfo) { AutoResetEvent autoEvent = (AutoResetEvent)stateInfo; Console.WriteLine("{0} Checking status {1,2}.", DateTime.Now.ToString("h:mm:ss.fff"), (++invokeCount).ToString()); if(invokeCount == maxCount) { // 重置计数器和信号主信号。 invokeCount = 0; autoEvent.Set(); } } }
复制代码

 

 

 

 

三、 System.Timers.Timer类

  这是一个相对较旧的类型,它和System.Threading.Timer一样,可以由工作者线程来执行回调方法,但同时它也可以在IDE环境中被拖到窗体控件上,这个时候它的行为非常类似于System.Windows.Forms.Timer类型,在消息过多时其定时并不准确。  System.Timers.Timer可以视为System.Threading.Timer的一个包装,其类型设计相对古老,不建议使用该定时器。

 

主要使用步骤如下:

1.   System.Timers.Timer myTimer =  new System.Timers.Timer( 1000 ); //实例化  设置时间间隔

2.    myTimer .Elapsed += new System.Timers.ElapsedEventHandler(函数名);  //给timer挂起事件 

3.   myTimer .AutoReset = true; //设置是执行一次(false)还是一直执行(true); 

4.  myTimer .Enabled = true; //是否执行System.Timers.Timer.Elapsed事件;

 

 

System.Timers.Timer例程代码:

复制代码
        System.Timers.Timer t = newSystem.Timers.Timer(5000); //设置时间间隔为5秒
        private void Form1_Load(object sender,EventArgs e)
        {
            t.Elapsed += newSystem.Timers.ElapsedEventHandler(Timer_TimesUp);
            t.AutoReset = false; //每到指定时间Elapsed事件是触发一次(false),还是一直触发(true)
        }
        
        private void btnStart_Click(objectsender, EventArgs e)
        {
            t.Enabled = true; //是否触发Elapsed事件
            t.Start();
        }
        private void Timer_TimesUp(objectsender, System.Timers.ElapsedEventArgs e)
        {
            //到达指定时间5秒触发该事件输出 HelloWorld!!!!
            System.Diagnostics.Debug.WriteLine("HelloWorld!!!!");
        }
        private void btnStop_Click(objectsender, EventArgs e)
        {
            t.Stop();
           System.Diagnostics.Debug.WriteLine("未到指定时间5秒提前终结!!!");
        }
复制代码

 

 

参考链接:http://www.cnblogs.com/DebugLZQ/archive/2012/08/05/2623669.html

     https://blog.csdn.net/zhouqt/article/details/51779264

      http://www.360doc.com/content/11/0812/11/1039473_139824496.shtml

 

个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解

 

一、依赖倒置(Dependency Inversion Principle)

依赖倒置是面向对象设计领域的一种软件设计原则。(其他的设计原则还有:单一职责原则、开放封闭原则、里式替换原则、接口分离原则,合称SOLID)

话说设计原则有什么用呢?

设计原则是无数编程前辈总结下来的经验,好似编程界的金科玉律。在我看来就像是武侠小说中武林秘籍,内功心法。熟练掌握设计原则,必定会在编程道路上顺风顺水,独霸一方。

言归正传,依赖倒置原则,依赖指的是什么?倒置又是什么呢?

先说说依赖,依赖是一种关系,A在某种情况下存在对B的需求关系,我们就可以看作A依赖B。

在生活中,鱼依赖于水而生存,水被鱼依赖;程序中,业务层依赖逻辑层,逻辑层依赖于数据层...

我们用面向对象编程来展示一下上面依赖关系:

复制代码
    /// <summary>
    /// 河水
    /// </summary>
    public class RiverWater
    {
        public void GiveNutrition()
        {
            Console.WriteLine("我是河水,我给小鱼提供养分。");
        }
    }
    /// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private RiverWater riverWater;
        public void Live()
        {
            riverWater = new RiverWater();
            riverWater.GiveNutrition();
        }
    }
复制代码

Fish内部存在对RiverWater的引用,也就是说Fish 依赖于RiverWarter。

依赖关系整明白了,我们再来看看依赖倒置原则的定义:(敲黑板,划重点)

1.上层模块不应该依赖底层模块,它们都应该依赖于抽象。
2.抽象不应该依赖于细节,细节应该依赖于抽象。

问题又来了,什么是上层模块和底层模块?

对于任何一个组织机构而言,它一定有架构的设计,有职能的划分。按照职能的重要性,自然而然就有了上下之分。并且,随着模块的粒度划分不同这种上层与底层模块会进行变动,也许某一模块相对于另外一模块它是底层,但是相对于其他模块它又可能是上层。拿一个公司架构来看,管理层就是上层,管理层之下就是底层。然后,我们再以部门为体系划分,各个部门经理以上部分是上层,之下的组织都可以称为底层。

由此,我们可以看到,在一个特定体系中,上层模块与底层模块可以按照决策能力高低为准绳进行划分。

映射到我们软件实际开发中,一般我们也会将软件进行模块划分,比如业务层、逻辑层和数据层。 业务层中是软件真正要进行的操作,也就是做什么;逻辑层是软件现阶段为了业务层的需求提供的实现细节,也就是怎么做;数据层指业务层和逻辑层所需要的数据模型。

因此,按照决策能力的高低进行模块划分。业务层自然就处于上层模块,逻辑层和数据层自然就归类为底层。

什么是抽象和细节?

抽象就是对一类事物或行为的概括,总结其共性。抽象往往是相对具体而言,具体也就是这里的细节。比如:人是抽象,张三、李四就是具体;水是抽象,河水,井水就是具体的;武功秘籍是抽象的,独孤九剑,葵花宝典是具体的;运动是抽象的,跑步,游泳是具体的...

映射到软件开发中,抽象可以是接口或者抽象类的形式:

复制代码
    public abstract class Water
    {
        public abstract void GiveNutrition();
    }
    /// <summary>
    /// 河水
    /// </summary>
    public class RiverWater : Water
    {
        public override void GiveNutrition()
        {
            Console.WriteLine("河水-提供养分。");
        }
    }
    /// <summary>
    /// 井水
    /// </summary>
    public class WellWater : Water
    {
        public override void GiveNutrition()
        {
            Console.WriteLine("井水-提供养分。");
        }
    }
复制代码

Warter是抽象类,是抽象的,RiverWarter、WellWater继承了Water,它们是具体的。

现在,搞清楚了上层模块、底层模块、抽象和具体。可以正式开始学习依赖倒置原则这个概念了。

先来看看我们平时开发的编码逻辑:

复制代码
/// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private RiverWater riverWater;
        public Fish()
        {
            riverWater = new RiverWater();
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            riverWater.GiveNutrition();
        }
    }
复制代码

我们创建了一条小鱼fish,它的生活靠河水riverWater。  

复制代码
    class Program
    {
        static void Main(string[] args)
        {
            Fish fish = new Fish();
            fish.Live();
        }
    }
复制代码

执行结果:

有一天,河水干涸了,小鱼的生活要靠井水wellWater。于是代码就要修改

复制代码
/// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private RiverWater riverWater;
        private WellWater wellWater;
        public Fish()
        {
            //riverWater = new RiverWater();
            wellWater = new WellWater();
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            //riverWater.GiveNutrition();
            wellWater.GiveNutrition();
        }
    }
复制代码

我们就要修改Fish类的代码。哪天,小鱼游到了湖水lakeWater里。代码又要修改

复制代码
    /// <summary>
    /// 湖水
    /// </summary>
    public class LakeWater : Water
    {
        public override void GiveNutrition()
        {
            Console.WriteLine("湖水-提供养分。");
        }
    }
    /// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private RiverWater riverWater;
        private WellWater wellWater;
        private LakeWater lakeWater;
        public Fish()
        {
            //riverWater = new RiverWater();
            //wellWater = new WellWater();
            lakeWater = new LakeWater();
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            //riverWater.GiveNutrition();
            //wellWater.GiveNutrition();
            lakeWater.GiveNutrition();
        }
    }
复制代码

我们添加了LakeWater这个新的实现类,再次修改Fish类。

这是最基础的演示代码,如果工程大了,代码复杂了,Fish面对需求变动时改动的地方会更多。那么问题来了:

有没有方法让Fish类变动的少一些?

依赖倒置原则正好适用于解决这类情况。下面,我们尝试运用依赖倒置原则对代码进行改造。

首先是上层模块和底层模块的拆分。按照决策能力高低或者重要性划分,Fish属于上层模块,RiverWater、WellWater 和 LakeWater 属于底层模块。

上层模块不应该依赖于底层模块。 Fish 这个类显然是依赖于 RiveWater/WellWater/LakeWater。Fish 类中 Live() 的能力完全依赖于属性riveWater/wellWater/lakeWater 对象。

上层和底层都应该依赖于抽象。因此我们要引入抽象——Water类。Fish类中 Live() 这个方法依赖于 Water的抽象方法,它没有限定养分的提供方式,任何 RiverWater、WellWater 或者是 LakeWater 都可以的。

复制代码
    /// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private Water water;
        public Fish()
        {
            water = new LakeWater();
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            warter.GiveNutrition();
        }
    }
复制代码

 运行结果:

到这一步,我们可以说是符合了上层不依赖于底层,依赖于抽象的准则了。

最后来说说我对倒置的理解:在未使用依赖倒置原则编码以前,鱼依赖具体的河水/井水,河水/井水是被依赖的。使用依赖倒置以后,鱼依赖于抽象的水,具体的河水/井水不再被依赖,反而它们要求实现抽象的水(细节依赖于抽象),这种依赖关系的改变称之为倒置。

二、控制反转(Inversion Of Control)

 控制反转(IOC)意思是对控制权的反转。

那么控制权指的是什么?又是怎么反转的?

以上面的例子来说,鱼(Fish类)依赖于水(Water类),所以Fish类内部控制着Water类的实例创建,这种方式可以理解为控制正转。虽然鱼已经依赖于抽象的水,Live()方法不会再因为生活水域的改变而改变,但水域变化时,我们还是要修改Fish类:

 

==>

现在我们改变这种方式,将Water类的实例化移到Fish外面:

复制代码
    /// <summary>
    /// 鱼
    /// </summary>
    public class Fish
    {
        private Water water;
        public Fish(Water _water)
        {
            water = _water;
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            water.GiveNutrition();
        }
    }
class Program { static void Main(string[] args) { Water water = new RiverWater(); Fish fish = new Fish(water); fish.Live(); Console.ReadKey(); } }
复制代码

这样,不论水域怎么变化,Fish 列都不需要修改了。Fish 把内部依赖的创建权力移交给了 Program 这个类中的 Main() 方法。也就是说 Fish 只关心依赖提供的功能,但并不关心依赖的创建。

这种思想其实就是 IOC,IOC 是一种新的设计模式,它对上层模块与底层模块进行了更进一步的解耦。控制反转的意思是反转了上层模块对于底层模块的依赖控制。比如上面代码,Fish 不再亲自创建 Water 对象,它将依赖的实例化的权力交接给了 Program。而 Program 在 IOC 中又指代了 IOC 容器 这个概念。 

IOC 模式最核心的地方就是在于依赖方与被依赖方之间,也就是上文中说的上层模块与底层模块之间引入了第三方,这个第三方统称为 IOC 容器,因为 IOC 容器的介入,导致上层模块对于它的依赖的实例化控制权发生变化,也就是所谓的控制反转的意思。

三、依赖注入(Dependency Injection)

依赖注入(DI),它是实现IOC的实现方式,动态地将某种依赖关系注入到对象之中。

回顾上面的例子,Fish 不在实例化创建Water,它就需要在外部(IOC 容器)赋值给它,这个赋值的动作有个专门的术语叫做注入(injection)。类似于,鱼生活在鱼缸里了,外接一个水龙头,水龙头另一头连接着水塔,这个水塔就好比是IOC容器,鱼不用关心生活在什么水里了,需要水时,打开水龙头(注入)就好了,至于水塔里装的是河水、井水还是海水,都不用考虑。

实现依赖注入有 3 种方式:

 1. 构造函数中注入 

复制代码
    public class Fish
    {
        private Water water;
        public Fish(Water _water)
        {
            water = _water;
        }
        public void Live()
        {
            Console.WriteLine("我的生活靠:");
            water.GiveNutrition();
        }
    }
复制代码

优点:在 Person 一开始创建的时候就确定好了依赖。 

缺点:后期无法更改依赖。

2. setter 方式注入 

复制代码
    public class Fish
    {
        private Water water;
        public Fish()
        {
        }
        public void setWater(Water _water)
        {
            water = _water;
        }
        public void Live()
        {
            if (water != null)
            {
                Console.WriteLine("我的生活靠:");
                water.GiveNutrition();
            }
        }
    }
复制代码

优点:Fish 对象在运行过程中可以灵活地更改依赖。 

缺点:Fish 对象运行时,可能会存在依赖项为 null 的情况,所以需要检测依赖项的状态

3. 接口注入

复制代码
    public class Fish : ISetWater
    {
        private Water water;
        public Fish()
        {
        }
        public void Live()
        {
            if (water != null)
            {
                Console.WriteLine("我的生活靠:");
                water.GiveNutrition();
            }
        }

        public void SetWater(Water _water)
        {
            water = _water;
        }
    }

    public interface ISetWater
    {
        void SetWater(Water water);
    }
复制代码

这种方式和 Setter 方式很相似,接口的存在,表明了一种依赖配置的能力。比如,鱼有 活鱼和死鱼,接口注入方式,我们就可以控制,只给活鱼注入配置。

四、总结

  1. 依赖倒置是面向对象开发领域中的软件设计原则,它倡导上层模块不依赖于底层模块,抽象不依赖细节。
  2. 依赖反转是遵守依赖倒置这个原则而提出来的一种设计模式,它引入了 IoC 容器的概念。
  3. 依赖注入是为了实现依赖反转的一种手段之一。
  4. 它们的本质是为了代码更加的“高内聚,低耦合”。

.net core 使用MD5加密解密字符串

 
复制代码
 /// <summary>
        /// 加密
        /// </summary>
        /// <param name="Text">要加密的文本</param>
        /// <param name="sKey">秘钥</param>
        /// <returns></returns>
        public static string Encrypt(string Text, string sKey="test")
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            byte[] inputByteArray;
            inputByteArray = Encoding.Default.GetBytes(Text);
            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0,8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            md4j= ret.ToString();
            return ret.ToString();
        }
复制代码
复制代码
/// <summary>
        /// 解密
        /// </summary>
        /// <param name="Text"></param>
        /// <param name="sKey"></param>
        /// <returns></returns>
        public static string Decrypt(string Text, string sKey = "test")
        {
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            int len;
            len = Text.Length / 2;
            byte[] inputByteArray = new byte[len];
            int x, i;
            for (x = 0; x < len; x++)
            {
                i = Convert.ToInt32(Text.Substring(x * 2, 2), 16);
                inputByteArray[x] = (byte)i;
            }
            des.Key = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            des.IV = ASCIIEncoding.ASCII.GetBytes(Md5Hash(sKey).Substring(0, 8));
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            return Encoding.Default.GetString(ms.ToArray());
        }
复制代码
复制代码
 /// <summary>
        /// 32位MD5加密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static string Md5Hash(string input)
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }
复制代码

调用加密 解密看效果

复制代码
      public static string md4j = "";
        static void Main(string[] args)
        {
            //加密
          Encrypt("123456");
          Decrypt(md4j);
        }
复制代码

 

posted @ 2018-10-15 10:19  ~雨落忧伤~  阅读(580)  评论(0编辑  收藏  举报