[C#6] 7-索引初始化器

时间:2022-04-23
本文章向大家介绍[C#6] 7-索引初始化器,主要内容包括0. 目录、1. 老版本的代码、2. 索引初始化器、3. Example、4. 总结、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

0. 目录

C#6 新增特性目录

1. 老版本的代码

1 private static void Main()
2 {
3     var dictionary = new Dictionary<int, string> {
4         { 1, "Value1" },
5         { 2, "Value2" },
6         { 3, "Value3" }
7     };
8 }

早C#3中引入的集合初始化器,可是让我们用上面的语法来在声明一个字典或者集合的时候立即初始化一些项进去,其实在C#3中这是个语法糖,实质编译后的结果是调用字典或者集合的Add方法逐一添加这些项。但是有一点小小的不直观。先看看这个版的IL吧:

 1 .method private hidebysig static void  Main() cil managed
 2 {
 3   .entrypoint
 4   // Code size       47 (0x2f)
 5   .maxstack  4
 6   .locals init ([0] class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string> dictionary)
 7   IL_0000:  nop
 8   IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::.ctor()
 9   IL_0006:  dup
10   IL_0007:  ldc.i4.1
11   IL_0008:  ldstr      "Value1"
12   IL_000d:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::Add(!0,
13                                                                                                                 !1)
14   IL_0012:  nop
15   IL_0013:  dup
16   IL_0014:  ldc.i4.2
17   IL_0015:  ldstr      "Value2"
18   IL_001a:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::Add(!0,
19                                                                                                                 !1)
20   IL_001f:  nop
21   IL_0020:  dup
22   IL_0021:  ldc.i4.3
23   IL_0022:  ldstr      "Value3"
24   IL_0027:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::Add(!0,
25                                                                                                                 !1)
26   IL_002c:  nop
27   IL_002d:  stloc.0
28   IL_002e:  ret
29 } // end of method Program::Main

本质是Add方法的调用.C#6引入了一种新语法来进一步的优化这种写法。

2. 索引初始化器

1 private static void Main()
2 {
3     var dictionary = new Dictionary<int, string>
4     {
5         [1] = "Value1",
6         [2] = "Value2",
7         [3] = "Value3"
8     };
9 }

看起来直观许多了吧,其实是一种语法改进。编译结果也有些许差异,如下:

 1 .method private hidebysig static void  Main() cil managed
 2 {
 3   .entrypoint
 4   // Code size       47 (0x2f)
 5   .maxstack  4
 6   .locals init ([0] class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string> dictionary)
 7   IL_0000:  nop
 8   IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::.ctor()
 9   IL_0006:  dup
10   IL_0007:  ldc.i4.1
11   IL_0008:  ldstr      "Value1"
12   IL_000d:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::set_Item(!0,
13                                                                                                                      !1)
14   IL_0012:  nop
15   IL_0013:  dup
16   IL_0014:  ldc.i4.2
17   IL_0015:  ldstr      "Value2"
18   IL_001a:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::set_Item(!0,
19                                                                                                                      !1)
20   IL_001f:  nop
21   IL_0020:  dup
22   IL_0021:  ldc.i4.3
23   IL_0022:  ldstr      "Value3"
24   IL_0027:  callvirt   instance void class [mscorlib]System.Collections.Generic.Dictionary`2<int32,string>::set_Item(!0,
25                                                                                                                      !1)
26   IL_002c:  nop
27   IL_002d:  stloc.0
28   IL_002e:  ret
29 } // end of method Program::Main

主要差异在于老语法是调用Add方法,新语法是用的索引器的set访问器(set_Item)。

既然是索引,那么就索引就不仅仅只能是int,也可以是string,任意的自定义类型。

3. Example

namespace csharp6
{
    internal class Program
    {
        public class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }

            private Dictionary<string, Address> _cache = new Dictionary<string, Address>();

            public Address this[string name]
            {
                get { return _cache[name]; }
                set { _cache[name] = value; }
            }
        }

        public class Address
        {
            public string Name { get; set; }
            public string Zip { get; set; }
        }

        private static void Main()
        {
            //string索引
            var colorMap = new Dictionary<string, ConsoleColor>
            {
                ["Error"] = ConsoleColor.Red,
                ["Information"] = ConsoleColor.Yellow,
                ["Verbose"] = ConsoleColor.White
            };

            //枚举索引
            var colors = new Dictionary<ConsoleColor, string>
            {
                [ConsoleColor.Red] = "#F00",
                [ConsoleColor.Green] = "#0F0",
            };

            //自定义类型的索引器支持
            Person person = new Person
            {
                Name = "blackheart",
                Age = 1,
                ["home"] = new Address { Name = "北京市", Zip = "100000" },
                ["work"] = new Address { Name = "南京市", Zip = "200000" }
            };

            //自定义类型索引
            var persons = new Dictionary<Person, List<Address>>
            {
                [new Person { Name = "blackheart", Age = 1 }] = new List<Address> {
                    new Address { Name = "北京市", Zip = "100000" }
                },
                [new Person { Name = "blackheart", Age = 1 }] = new List<Address> {
                    new Address { Name = "南京市", Zip = "200000" }
                },
            };
        }
    }
}

4. 总结

从本质来看,[xxx]=yyy这种语法,xxx可以是任意类型,凡是有索引器支持的类型,均可以使用这种语法。简单直接明了。