基本类型(一)

基本类型

字符、字符串和文本处理

字符

基本概念

  1. 基本结构

    • .Net Framework中,字符总是表示成16位的Unicode代码值。
    • 每个字符都是System.Char的实例,注意,该类型为值类型。
    • Char.MaxValue='/uffff',表示65535。
  2. Culture(字符或者字符串有文化的差异,需要注意)

  3. 转换(效率由高到低)

    • 转型(强制类型转换)

      Char a = (Int32)65;// A 
      
    • 使用Convert类型

      Char a = Convert.ToChar(65); // A
      
    • 使用IConvertible接口

      Char a = (IConvertible(65)).ToChar(null); // A
      
      
  4. 思考这两种写法有什么不同?

    // 思考:这两种写法有什么不同?
    char b = unchecked((Char)(65536*2 + 65));
    Console.WriteLine(b);
    Char d = unchecked(Convert.ToChar(70000));// 这种是编译不过的
    Console.WriteLine(d);
    
    • IL分析

      // 有效的IL代码
      .entrypoint
      // 代码大小       30 (0x1e)
      .maxstack  1
      .locals init (char V_0,
               char V_1)
      IL_0000:  nop
      IL_0001:  ldc.i4.s   65 // 实际强制转换会减去65536的整数倍后再进行转换。
      IL_0003:  stloc.0
      IL_0004:  ldloc.0
      IL_0005:  call       void [mscorlib]System.Console::WriteLine(char)
      IL_000a:  nop
      IL_000b:  ldc.i4     0x11170 // 已经超过Char.MaxValue
      IL_0010:  call       char [mscorlib]System.Convert::ToChar(int32)
      IL_0015:  stloc.1
      IL_0016:  ldloc.1
      IL_0017:  call       void [mscorlib]System.Console::WriteLine(char)
      IL_001c:  nop
      IL_001d:  ret
      

参考内容

  1. 字符集介绍
  2. UniCode码介绍
  3. UniCode编码表

字符串

String

基本概念
  1. 基本结构

    • string表示一个不可变的顺序字符集(immutable)。
    • String对象(它的字符数组)总是存在于堆上。
      • 特别说明一点,struct上面的string也不例外,若是局部变量,在Stack上,若是引用类型的成员,则在Heap上。但是注意的是,当struct拷贝一个副本的时候,引用的堆控件也会重新分配初始化
      • 关于struct的说明,可以参考MSDN-Struct
    • string不允许使用new关键字构造string对象。
    • 字符串换行建议使用Environment.NewLine,而不是/r/n。
    • 编程技巧:要在序号比较前更改字符串中的字符的大小写,应该使用String.ToUpperInvariant进行正规化(normalizing),微软对执行大写比较代码进行过优化。
  2. 语言文化(Culture)

    • 后续补上,目前用到不多
  3. 字符串留用(string interning)

    • 原理

      1. 原理说明
         CLR初始化的时候创建一个内部哈希表,在这个表中,键(key)是字符串,而值(value)是对托管堆中的string对象的引用,开始时候,哈希表为空。
         暴露的API:
         - public static String Intern(String str);
         - public static String IsInterned(String str);
      2. 影响CLR的特性
         - CompilationRelaxationAttribute
      
      
  4. 字符串池

高效处理字符串

  1. StringBuilder
  2. ToString
    • IFormatProvider
  3. Parse

安全字符串

  1. 后续整理

文本处理

编码(后续整理)

  1. UTF-16(Unicode编码)

  2. UTF-8

    // 简单案例
    public class EncodingTest
    {
        public static void Run()
        {
            string str = "hello,world";
            // 获取utf8
            var utf8Encoding = Encoding.UTF8;
            // 将字符串编译成字符串数组
            var encodingBytes = utf8Encoding.GetBytes(str);
            // 显示编码好的值
            Console.WriteLine(BitConverter.ToString(encodingBytes));
            // 解码
            var str2 = utf8Encoding.GetString(encodingBytes);
            Console.WriteLine(str2);
            Console.WriteLine("是否相等:" + Object.ReferenceEquals(str, str2));
        }
    }
    

枚举类型和位标志

基本概念

  1. 枚举是值类型

  2. 使用枚举的理由

    • 枚举类型使程序更容易编写、阅读和维护。
    • 枚举是强类型的,不容易写错。
  3. 常见的用法

    public class EnumTest
    {
        public static void Run()
        {
            // 强制转换
            ColorEnum color = (ColorEnum)1; // Pink
            if(color == ColorEnum.Pink)
            {
                Console.WriteLine("强制转换成功");
            }
            // 数字转换
            int num = (int)color; // 1
            Console.WriteLine("转换成数字:" + num); 
            // 获取枚举项的名称
            string name = Enum.GetName(typeof(ColorEnum), 1); // Pink
            Console.WriteLine("查找到的枚举值为1的名称:" + name);
        }
    }
    
    public enum ColorEnum
    {
        Orange,
        Pink
    }
    

位标志

  1. 普通枚举和位标志的区别

    • 位标志为可以用来表示一组可以组合的枚举类型。
    • 位标志表示位集合。
    • 枚举值可以从0开始,按2的n-1次方表示,但是不一定是2的n次方。
    • 可以用[Flags]特性标注位标志。
  2. 案例分析

    public class Test
    {
        public static void Main(string[] args)
        {
            // 位标志
            MyFlagEnum actions = MyFlagEnum.Close | MyFlagEnum.Open;// 增加,等于十进制的3,并装箱到actions指向的Heap中MyFlagEnum
            Console.WriteLine(actions.ToString("F")); // Close,Open
            MyFlagEnum myFlag = (MyFlagEnum)Enum.Parse(typeof(MyFlagEnum), "open", true);
            Console.WriteLine(myFlag.ToString("F"));// Open
            myFlag = (MyFlagEnum)Enum.Parse(typeof(MyFlagEnum), "2", false);
            Console.WriteLine(myFlag.ToString("F"));// Close
            myFlag = (MyFlagEnum)Enum.Parse(typeof(MyFlagEnum), "3", false);
            Console.WriteLine(myFlag.ToString("F")); // Open,Close
            myFlag = MyFlagEnum.All | MyFlagEnum.None; // 为什么这里只会出现ALL,从最大值计算减掉当前值,向下找组合,但是0不会给找到。
            Console.WriteLine(myFlag.ToString("F"));// ALL
        }
    }
    
    [Flags]
    public enum MyFlagEnum
    {
        None = 0,
        Open = 0x0001,
        Close = 0x0002,
        All = 0x001F //十进制31
    }
    
    • IL代码分析

      .class public auto ansi beforefieldinit ILLearning.Test
             extends [mscorlib]System.Object
      {
        .method public hidebysig static void  Main(string[] args) cil managed
        {
          .entrypoint
          // 代码大小       198 (0xc6)
          .maxstack  3
          .locals init (valuetype ILLearning.MyFlagEnum V_0,
                   valuetype ILLearning.MyFlagEnum V_1)
          IL_0000:  nop
          IL_0001:  ldc.i4.3
          IL_0002:  stloc.0
          IL_0003:  ldloc.0
          IL_0004:  box        ILLearning.MyFlagEnum
          IL_0009:  ldstr      "F"
          IL_000e:  call       instance string [mscorlib]System.Enum::ToString(string)
          IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_0018:  nop
          IL_0019:  ldtoken    ILLearning.MyFlagEnum
          IL_001e:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
          IL_0023:  ldstr      "open"
          IL_0028:  ldc.i4.1  // true,在IL中表示1,false表示0
          IL_0029:  call       object [mscorlib]System.Enum::Parse(class [mscorlib]System.Type,
                                                                   string,
                                                                   bool)
          IL_002e:  unbox.any  ILLearning.MyFlagEnum
          IL_0033:  stloc.1
          IL_0034:  ldloc.1
          IL_0035:  box        ILLearning.MyFlagEnum
          IL_003a:  ldstr      "F"
          IL_003f:  call       instance string [mscorlib]System.Enum::ToString(string)
          IL_0044:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_0049:  nop
          IL_004a:  ldtoken    ILLearning.MyFlagEnum
          IL_004f:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
          IL_0054:  ldstr      "2"
          IL_0059:  ldc.i4.0
          IL_005a:  call       object [mscorlib]System.Enum::Parse(class [mscorlib]System.Type,
                                                                   string,
                                                                   bool)
          IL_005f:  unbox.any  ILLearning.MyFlagEnum
          IL_0064:  stloc.1
          IL_0065:  ldloc.1
          IL_0066:  box        ILLearning.MyFlagEnum
          IL_006b:  ldstr      "F"
          IL_0070:  call       instance string [mscorlib]System.Enum::ToString(string)
          IL_0075:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_007a:  nop
          IL_007b:  ldtoken    ILLearning.MyFlagEnum
          IL_0080:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
          IL_0085:  ldstr      "3"
          IL_008a:  ldc.i4.0
          IL_008b:  call       object [mscorlib]System.Enum::Parse(class [mscorlib]System.Type,
                                                                   string,
                                                                   bool)
          IL_0090:  unbox.any  ILLearning.MyFlagEnum
          IL_0095:  stloc.1
          IL_0096:  ldloc.1
          IL_0097:  box        ILLearning.MyFlagEnum
          IL_009c:  ldstr      "F"
          IL_00a1:  call       instance string [mscorlib]System.Enum::ToString(string)
          IL_00a6:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_00ab:  nop
          IL_00ac:  ldc.i4.s   31
          IL_00ae:  stloc.1
          IL_00af:  ldloc.1
          IL_00b0:  box        ILLearning.MyFlagEnum
          IL_00b5:  ldstr      "F"
          IL_00ba:  call       instance string [mscorlib]System.Enum::ToString(string)
          IL_00bf:  call       void [mscorlib]System.Console::WriteLine(string)
          IL_00c4:  nop
          IL_00c5:  ret
        } // end of method Test::Main
      
        .method public hidebysig specialname rtspecialname 
                instance void  .ctor() cil managed
        {
          // 代码大小       8 (0x8)
          .maxstack  8
          IL_0000:  ldarg.0
          IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
          IL_0006:  nop
          IL_0007:  ret
        } // end of method Test::.ctor
      
      } // end of class ILLearning.Test
      
      .class public auto ansi sealed ILLearning.MyFlagEnum
             extends [mscorlib]System.Enum
      {
        .custom instance void [mscorlib]System.FlagsAttribute::.ctor() = ( 01 00 00 00 ) 
        .field public specialname rtspecialname int32 value__
        .field public static literal valuetype ILLearning.MyFlagEnum None = int32(0x00000000)
        .field public static literal valuetype ILLearning.MyFlagEnum Open = int32(0x00000001)
        .field public static literal valuetype ILLearning.MyFlagEnum Close = int32(0x00000002)
        .field public static literal valuetype ILLearning.MyFlagEnum All = int32(0x0000001F)
      } // end of class ILLearning.MyFlagEnum
      

数组

基本概念

  1. 数组为引用类型,是在托管堆中分配的。
  2. 数组隐式继承自System.Array

数组转型

对于元素类型为引用类型的数组,CLR允许将数组元素从一种类型转型为另一种。

  • 前提是数组维数相同,而且必须存在从元素源类型到目标类型的隐式转换或者显式转换。

  • CLR不允许将值类型转换成其他任何类型。

    // 测试类型转换
    FileStream[,] fs = new FileStream[5, 10];
    // 隐式转换
    object[,] obj = fs;// 支持向上转型,协变性
    // 转型失败一:维度不同,不允许转型
    // Stream[] fs2 = obj;
    // 显示转型,成功
    Stream[,] fs2 = (Stream[,])obj;// 逆变性
    // 转型失败二:编译没有问题,运行有问题,类型不匹配
    // string[,] arrStr = (string[,])obj;
    // 值类型测试
    Int32[] arrInt = new int[10];
    // 转型失败三:值类型不允许转换成引用类型
    // object[] arrObject = arrInt;
    // 转型失败四:值类型不允许转换成其他值类型
    //Double[] arrDouble = arrInt;
    

数组内部工作原理

  1. 隐式派生自System.Array
  2. 所有数组隐式实现IEnumerable、ICollection和IList。

数组的内部工作原理

  • CLR支持两种不同的数组

    • 下限为0的一维数组,也称SZ(single-dimensional,zero-based)数组或者向量(Vector)。
    • 下限未知的一维或多维数组。
  • 演示二维数组的三种方式(安全、交错和不安全)

    using System;
    
    namespace ILLearning
    {
        public class ArrayDemoTest
        {
            private static int c_numElements = 10000;
    
            public static void Main()
            {
                Int32[,] a2Dim = new Int32[c_numElements, c_numElements];
    
                // 声明交错数组(向量构成的向量)
                int[][] aJagged = new Int32[c_numElements][];
                for (int i = 0; i <c_numElements; i++)
                {
                    aJagged[i] = new Int32[c_numElements];
                }
                Safe2DimArrayAccess(a2Dim);
                SafeJaggedArrayAccess(aJagged);
                Unsafe2DimArrayAccess(a2Dim);
            }
    
            /// <summary>
            /// CLR安全方式访问
            /// </summary>
            /// <param name="a"></param>
            /// <returns></returns>
            private static Int32 Safe2DimArrayAccess(Int32[,] a)
            {
                Int32 sum = 0;
                for (int i = 0; i < c_numElements; i++)
                {
                    for (int j = 0; j < c_numElements; j++)
                    {
                        sum += a[i, j];
                    }
                }
                return sum;
            }
    
            /// <summary>
            /// 交错访问
            /// </summary>
            /// <param name="a"></param>
            /// <returns></returns>
            private static Int32 SafeJaggedArrayAccess(Int32[][] a)
            {
                Int32 sum = 0;
                for (int i = 0; i < c_numElements; i++)
                {
                    for (int j = 0; j < c_numElements; j++)
                    {
                        sum += a[i][j];
                    }
                }
                return sum;
            }
    
            private static unsafe Int32 Unsafe2DimArrayAccess(Int32[,] a)
            {
                Int32 sum = 0;
                // fixed的作用:
                /*
                 fixed 语句可防止垃圾回收器重新定位可移动的变量。
                 fixed 语句仅允许存在于不安全的上下文中。
                 fixed 还可用于创建固定大小的缓冲区。
                 */
                fixed (Int32* pi = a)// 声明指针pi,指向CLR类型a
                {
                    for (Int32 i = 0; i < c_numElements; i++)
                    {
                        Int32 baseofDim = i * c_numElements;
                        for (int j = 0; j < c_numElements; j++)
                        {
                            sum += pi[baseofDim+j];
                        }
                    }
                }
                return sum;
            }
        }
    }
    
    • 待分析unsafe代码IL代码

      .method private hidebysig static int32 
                Unsafe2DimArrayAccess(int32[0...,0...] a) cil managed
        {
          // 代码大小       118 (0x76)
          .maxstack  4
          .locals init (int32 V_0,
                   int32* V_1,
                   int32[0...,0...] pinned V_2,
                   int32 V_3,
                   int32 V_4,
                   int32 V_5,
                   bool V_6,
                   bool V_7,
                   int32 V_8)
          IL_0000:  nop
          IL_0001:  ldc.i4.0
          IL_0002:  stloc.0
          IL_0003:  ldarg.0
          IL_0004:  dup
          IL_0005:  stloc.2
          IL_0006:  brfalse.s  IL_0010
      
          IL_0008:  ldloc.2
          IL_0009:  callvirt   instance int32 [mscorlib]System.Array::get_Length()
          IL_000e:  brtrue.s   IL_0015
      
          IL_0010:  ldc.i4.0
          IL_0011:  conv.u
          IL_0012:  stloc.1
          IL_0013:  br.s       IL_001f
      
          IL_0015:  ldloc.2
          IL_0016:  ldc.i4.0
          IL_0017:  ldc.i4.0
          IL_0018:  call       instance int32& int32[0...,0...]::Address(int32,
                                                                         int32)
          IL_001d:  conv.u
          IL_001e:  stloc.1
          IL_001f:  nop
          IL_0020:  ldc.i4.0
          IL_0021:  stloc.3
          IL_0022:  br.s       IL_005d
      
          IL_0024:  nop
          IL_0025:  ldloc.3
          IL_0026:  ldsfld     int32 ILLearning.ArrayDemoTest::c_numElements
          IL_002b:  mul
          IL_002c:  stloc.s    V_4
          IL_002e:  ldc.i4.0
          IL_002f:  stloc.s    V_5
          IL_0031:  br.s       IL_0049
      
          IL_0033:  nop
          IL_0034:  ldloc.0
          IL_0035:  ldloc.1
          IL_0036:  ldloc.s    V_4
          IL_0038:  ldloc.s    V_5
          IL_003a:  add
          IL_003b:  conv.i
          IL_003c:  ldc.i4.4
          IL_003d:  mul
          IL_003e:  add
          IL_003f:  ldind.i4
          IL_0040:  add
          IL_0041:  stloc.0
          IL_0042:  nop
          IL_0043:  ldloc.s    V_5
          IL_0045:  ldc.i4.1
          IL_0046:  add
          IL_0047:  stloc.s    V_5
          IL_0049:  ldloc.s    V_5
          IL_004b:  ldsfld     int32 ILLearning.ArrayDemoTest::c_numElements
          IL_0050:  clt
          IL_0052:  stloc.s    V_6
          IL_0054:  ldloc.s    V_6
          IL_0056:  brtrue.s   IL_0033
      
          IL_0058:  nop
          IL_0059:  ldloc.3
          IL_005a:  ldc.i4.1
          IL_005b:  add
          IL_005c:  stloc.3
          IL_005d:  ldloc.3
          IL_005e:  ldsfld     int32 ILLearning.ArrayDemoTest::c_numElements
          IL_0063:  clt
          IL_0065:  stloc.s    V_7
          IL_0067:  ldloc.s    V_7
          IL_0069:  brtrue.s   IL_0024
      
          IL_006b:  nop
          IL_006c:  ldnull
          IL_006d:  stloc.2
          IL_006e:  ldloc.0
          IL_006f:  stloc.s    V_8
          IL_0071:  br.s       IL_0073
      
          IL_0073:  ldloc.s    V_8
          IL_0075:  ret
        } // end of method ArrayDemoTest::Unsafe2DimArrayAccess
      

不安全的数组(后续补充)

其他主题

数组的传递和返回

  1. 数组作为实参传递给方法时候,实际传递的是数组的引用。

  2. Array.Copy方法执行的是浅拷贝,浅拷贝怎么理解?

    public class Test
    {
        public static void Main(string[] args)
        {
            // Array.Copy
            string[] hhs = new string[3];
            hhs[0] = "hi";
            hhs[1] = ",";
            string[] hhs2 = new string[5];
            hhs.CopyTo(hhs2,0);// 实际上,这里的效果是深复制,应该是两次New都有在堆中分配了内存空间,不会再单独开辟栈引用,指向其他的内存空间
        }
    }
    
    • 主要IL代码分析

      .module test.exe
      // MVID: {B90E3704-F778-4BDE-8F93-5D1D1296068D}
      .imagebase 0x00400000
      .file alignment 0x00000200
      .stackreserve 0x00100000
      .subsystem 0x0003       // WINDOWS_CUI
      .corflags 0x00000001    //  ILONLY
      // Image base: 0x06870000
      
      
      // =============== CLASS MEMBERS DECLARATION ===================
      
      .class public auto ansi beforefieldinit ILLearning.Test
             extends [mscorlib]System.Object
      {
        .method public hidebysig static void  Main(string[] args) cil managed
        {
          .entrypoint
          // 代码大小       41 (0x29)
          .maxstack  3
          .locals init (string[] V_0,
                   string[] V_1)
          IL_0000:  nop
          IL_0001:  ldc.i4.3
          IL_0002:  newarr     [mscorlib]System.String // 创建数组hhs
          IL_0007:  stloc.0
          IL_0008:  ldloc.0
          IL_0009:  ldc.i4.0
          IL_000a:  ldstr      "hi"
          IL_000f:  stelem.ref // 用计算堆栈上的对象 ref 值(O 类型)替换给定索引处的数组元素。
          IL_0010:  ldloc.0
          IL_0011:  ldc.i4.1
          IL_0012:  ldstr      ","
          IL_0017:  stelem.ref
          IL_0018:  ldc.i4.5
          IL_0019:  newarr     [mscorlib]System.String
          IL_001e:  stloc.1
          IL_001f:  ldloc.0
          IL_0020:  ldloc.1
          IL_0021:  ldc.i4.0
          IL_0022:  callvirt   instance void [mscorlib]System.Array::CopyTo(class [mscorlib]System.Array,
                                                                            int32)
          IL_0027:  nop
          IL_0028:  ret
        } // end of method Test::Main
      
  3. 数组的实参传递

    // 测试数组传递的是引用
    public static void Test()
    {           
     string[] hhs = new string[3];
        hhs[0] = "hi";
        hhs[1] = ",";
        foreach (var item in hhs)
        {
            Console.WriteLine(item);// hhs[0] = hi
        }
        SayHi(hhs);
        foreach (var item in hhs)
        {
            Console.WriteLine(item);// hhs[0] = "HelloWorld"
        }
    }
    
    public static void SayHi(string[] hehes)
    {
        if (hehes != null && hehes.Count() > 1)
        {
            hehes[0] = "HelloWorld";
        }
    }
    

创建下限非零的数组

  • 演示案例

    // 目前比较少用
    public sealed class DynamicArrays
    {
        public static void Run()
        {
            Int32[] lowerBounds = { 2005, 1 };
            Int32[] lengths = { 5, 4 };
            Decimal[,] quarterlyRevernue = (Decimal[,])Array.CreateInstance(typeof(Decimal), lengths, lowerBounds);
            Console.WriteLine("{0,4} {1,9} {2,9} {3,9} {4,9}", "Year","Q1", "Q2", "Q3", "Q4");
            Int32 firstYear = quarterlyRevernue.GetLowerBound(0);
            Int32 lastYear = quarterlyRevernue.GetUpperBound(0);
            int firstQuarter = quarterlyRevernue.GetLowerBound(1);
            int lastQuarter = quarterlyRevernue.GetUpperBound(1);
    
            for(Int32 year = firstYear;year <= lastYear; year++)
            {
                Console.Write(year + " ");
                for (int quarter = firstQuarter; quarter <= lastQuarter; quarter++)
                {
                    Console.Write("{0,9:C}", quarterlyRevernue[year, quarter]);
                }
                Console.WriteLine();
            }
        }
    }
    

可空值类型

基本概念

  1. System.Nullable<T>仍然为值类型
  2. ??可空符号优化
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容