基本類型(一)

基本類型

字符、字符串和文本處理

字符

基本概念

  1. 基本結(jié)構(gòu)

    • .Net Framework中,字符總是表示成16位的Unicode代碼值。
    • 每個(gè)字符都是System.Char的實(shí)例,注意,該類型為值類型。
    • Char.MaxValue='/uffff',表示65535。
  2. Culture(字符或者字符串有文化的差異,需要注意)

  3. 轉(zhuǎn)換(效率由高到低)

    • 轉(zhuǎn)型(強(qiáng)制類型轉(zhuǎn)換)

      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 // 實(shí)際強(qiáng)制轉(zhuǎn)換會減去65536的整數(shù)倍后再進(jìn)行轉(zhuǎn)換。
      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 // 已經(jīng)超過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
      

參考內(nèi)容

  1. 字符集介紹
  2. UniCode碼介紹
  3. UniCode編碼表

字符串

String

基本概念
  1. 基本結(jié)構(gòu)

    • string表示一個(gè)不可變的順序字符集(immutable)。
    • String對象(它的字符數(shù)組)總是存在于堆上。
      • 特別說明一點(diǎn),struct上面的string也不例外,若是局部變量,在Stack上,若是引用類型的成員,則在Heap上。但是注意的是,當(dāng)struct拷貝一個(gè)副本的時(shí)候,引用的堆控件也會重新分配初始化
      • 關(guān)于struct的說明,可以參考MSDN-Struct
    • string不允許使用new關(guān)鍵字構(gòu)造string對象。
    • 字符串換行建議使用Environment.NewLine,而不是/r/n。
    • 編程技巧:要在序號比較前更改字符串中的字符的大小寫,應(yīng)該使用String.ToUpperInvariant進(jìn)行正規(guī)化(normalizing),微軟對執(zhí)行大寫比較代碼進(jìn)行過優(yōu)化。
  2. 語言文化(Culture)

    • 后續(xù)補(bǔ)上,目前用到不多
  3. 字符串留用(string interning)

    • 原理

      1. 原理說明
         CLR初始化的時(shí)候創(chuàng)建一個(gè)內(nèi)部哈希表,在這個(gè)表中,鍵(key)是字符串,而值(value)是對托管堆中的string對象的引用,開始時(shí)候,哈希表為空。
         暴露的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. 后續(xù)整理

文本處理

編碼(后續(xù)整理)

  1. UTF-16(Unicode編碼)

  2. UTF-8

    // 簡單案例
    public class EncodingTest
    {
        public static void Run()
        {
            string str = "hello,world";
            // 獲取utf8
            var utf8Encoding = Encoding.UTF8;
            // 將字符串編譯成字符串?dāng)?shù)組
            var encodingBytes = utf8Encoding.GetBytes(str);
            // 顯示編碼好的值
            Console.WriteLine(BitConverter.ToString(encodingBytes));
            // 解碼
            var str2 = utf8Encoding.GetString(encodingBytes);
            Console.WriteLine(str2);
            Console.WriteLine("是否相等:" + Object.ReferenceEquals(str, str2));
        }
    }
    

枚舉類型和位標(biāo)志

基本概念

  1. 枚舉是值類型

  2. 使用枚舉的理由

    • 枚舉類型使程序更容易編寫、閱讀和維護(hù)。
    • 枚舉是強(qiáng)類型的,不容易寫錯(cuò)。
  3. 常見的用法

    public class EnumTest
    {
        public static void Run()
        {
            // 強(qiáng)制轉(zhuǎn)換
            ColorEnum color = (ColorEnum)1; // Pink
            if(color == ColorEnum.Pink)
            {
                Console.WriteLine("強(qiáng)制轉(zhuǎn)換成功");
            }
            // 數(shù)字轉(zhuǎn)換
            int num = (int)color; // 1
            Console.WriteLine("轉(zhuǎn)換成數(shù)字:" + num); 
            // 獲取枚舉項(xiàng)的名稱
            string name = Enum.GetName(typeof(ColorEnum), 1); // Pink
            Console.WriteLine("查找到的枚舉值為1的名稱:" + name);
        }
    }
    
    public enum ColorEnum
    {
        Orange,
        Pink
    }
    

位標(biāo)志

  1. 普通枚舉和位標(biāo)志的區(qū)別

    • 位標(biāo)志為可以用來表示一組可以組合的枚舉類型。
    • 位標(biāo)志表示位集合。
    • 枚舉值可以從0開始,按2的n-1次方表示,但是不一定是2的n次方。
    • 可以用[Flags]特性標(biāo)注位標(biāo)志。
  2. 案例分析

    public class Test
    {
        public static void Main(string[] args)
        {
            // 位標(biāo)志
            MyFlagEnum actions = MyFlagEnum.Close | MyFlagEnum.Open;// 增加,等于十進(jìn)制的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; // 為什么這里只會出現(xiàn)ALL,從最大值計(jì)算減掉當(dāng)前值,向下找組合,但是0不會給找到。
            Console.WriteLine(myFlag.ToString("F"));// ALL
        }
    }
    
    [Flags]
    public enum MyFlagEnum
    {
        None = 0,
        Open = 0x0001,
        Close = 0x0002,
        All = 0x001F //十進(jìn)制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
      

數(shù)組

基本概念

  1. 數(shù)組為引用類型,是在托管堆中分配的。
  2. 數(shù)組隱式繼承自System.Array

數(shù)組轉(zhuǎn)型

對于元素類型為引用類型的數(shù)組,CLR允許將數(shù)組元素從一種類型轉(zhuǎn)型為另一種。

  • 前提是數(shù)組維數(shù)相同,而且必須存在從元素源類型到目標(biāo)類型的隱式轉(zhuǎn)換或者顯式轉(zhuǎn)換。

  • CLR不允許將值類型轉(zhuǎn)換成其他任何類型。

    // 測試類型轉(zhuǎn)換
    FileStream[,] fs = new FileStream[5, 10];
    // 隱式轉(zhuǎn)換
    object[,] obj = fs;// 支持向上轉(zhuǎn)型,協(xié)變性
    // 轉(zhuǎn)型失敗一:維度不同,不允許轉(zhuǎn)型
    // Stream[] fs2 = obj;
    // 顯示轉(zhuǎn)型,成功
    Stream[,] fs2 = (Stream[,])obj;// 逆變性
    // 轉(zhuǎn)型失敗二:編譯沒有問題,運(yùn)行有問題,類型不匹配
    // string[,] arrStr = (string[,])obj;
    // 值類型測試
    Int32[] arrInt = new int[10];
    // 轉(zhuǎn)型失敗三:值類型不允許轉(zhuǎn)換成引用類型
    // object[] arrObject = arrInt;
    // 轉(zhuǎn)型失敗四:值類型不允許轉(zhuǎn)換成其他值類型
    //Double[] arrDouble = arrInt;
    

數(shù)組內(nèi)部工作原理

  1. 隱式派生自System.Array
  2. 所有數(shù)組隱式實(shí)現(xiàn)IEnumerable、ICollection和IList。

數(shù)組的內(nèi)部工作原理

  • CLR支持兩種不同的數(shù)組

    • 下限為0的一維數(shù)組,也稱SZ(single-dimensional,zero-based)數(shù)組或者向量(Vector)。
    • 下限未知的一維或多維數(shù)組。
  • 演示二維數(shù)組的三種方式(安全、交錯(cuò)和不安全)

    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];
    
                // 聲明交錯(cuò)數(shù)組(向量構(gòu)成的向量)
                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>
            /// 交錯(cuò)訪問
            /// </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 還可用于創(chuàng)建固定大小的緩沖區(qū)。
                 */
                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
      

不安全的數(shù)組(后續(xù)補(bǔ)充)

其他主題

數(shù)組的傳遞和返回

  1. 數(shù)組作為實(shí)參傳遞給方法時(shí)候,實(shí)際傳遞的是數(shù)組的引用。

  2. Array.Copy方法執(zhí)行的是淺拷貝,淺拷貝怎么理解?

    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);// 實(shí)際上,這里的效果是深復(fù)制,應(yīng)該是兩次New都有在堆中分配了內(nèi)存空間,不會再單獨(dú)開辟棧引用,指向其他的內(nèi)存空間
        }
    }
    
    • 主要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 // 創(chuàng)建數(shù)組hhs
          IL_0007:  stloc.0
          IL_0008:  ldloc.0
          IL_0009:  ldc.i4.0
          IL_000a:  ldstr      "hi"
          IL_000f:  stelem.ref // 用計(jì)算堆棧上的對象 ref 值(O 類型)替換給定索引處的數(shù)組元素。
          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. 數(shù)組的實(shí)參傳遞

    // 測試數(shù)組傳遞的是引用
    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";
        }
    }
    

創(chuàng)建下限非零的數(shù)組

  • 演示案例

    // 目前比較少用
    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. ??可空符號優(yōu)化
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容