使用 C# 可以在单条语句中实例化对象或集合并执行成员分配。
对象初始值设定项
使用对象初始值设定项,你可以在创建对象时向对象的任何可访问字段或属性分配值,而无需调用后跟赋值语句行的构造函数。 利用对象初始值设定项语法,你可为构造函数指定参数或忽略参数(以及括号语法)。 以下示例演示如何使用具有命名类型 Cat
的对象初始值设定项以及如何调用无参数构造函数。 请注意,自动实现的属性在 Cat
类中的用法。
public class Cat
{
public int Age { get; set; }
public string Name { get; set; }
public Cat()
{
}
public Cat(string name)
{
this.Name = name;
}
}
Cat cat = new Cat { Age = 10, Name = "Fluffy" };
Cat sameCat = new Cat("Fluffy"){ Age = 10 };
对象初始值设定项语法允许你创建一个实例,然后将具有其分配属性的新建对象指定给赋值中的变量。
从 C# 6 开始,除了分配字段和属性外,对象初始值设定项还可以设置索引器。 请思考这个基本的 Matrix
类:
public class Matrix
{
private double[,] storage = new double[3, 3];
public double this[int row, int column]
{
// 嵌入的数组将酌情抛出超出范围的异常。
get { return storage[row, column]; }
set { storage[row, column] = value; }
}
}
可以使用以下代码初始化标识矩阵:
var identity = new Matrix
{
[0, 0] = 1.0,
[0, 1] = 0.0,
[0, 2] = 0.0,
[1, 0] = 0.0,
[1, 1] = 1.0,
[1, 2] = 0.0,
[2, 0] = 0.0,
[2, 1] = 0.0,
[2, 2] = 1.0,
};
包含可访问资源库的任何可访问索引器都可以用作对象初始值设定项中的表达式之一,这与参数的数量或类型无关。 索引参数构成左侧赋值,而表达式右侧是值。 例如,如果 IndexersExample
具有适当的索引器,则这些都是有效的:
var thing = new IndexersExample {
name = "object one",
[1] = '1',
[2] = '4',
[3] = '9',
Size = Math.PI,
['C',4] = "Middle C"
}
对于要进行编译的前面的代码,IndexersExample
类型必须具有以下成员:
public string name;
public double Size { set { ... }; }
public char this[int i] { set { ... }; }
public string this[char c, int i] { set { ... }; }
具有匿名类型的对象初始值设定项
尽管对象初始值设定项可用于任何上下文中,但它们在 LINQ 查询表达式中特别有用。 查询表达式常使用只能通过使用对象初始值设定项进行初始化的匿名类型,如下面的声明所示。
var pet = new { Age = 10, Name = "Fluffy" };
利用匿名类型,LINQ 查询表达式中的 select
子句可以将原始序列的对象转换为其值和形状可能不同于原始序列的对象。 如果你只想存储某个序列中每个对象的部分信息,则这很有用。 在下面的示例中,假定产品对象 (p
) 包含很多字段和方法,而你只想创建包含产品名和单价的对象序列。
var productInfos =
from p in products
select new { p.ProductName, p.UnitPrice };
执行此查询时,productInfos
变量将包含一系列对象,这些对象可以在 foreach
语句中进行访问,如下面的示例所示:
foreach(var p in productInfos){...}
新的匿名类型中的每个对象都具有两个公共属性,这两个属性接收与原始对象中的属性或字段相同的名称。 你还可在创建匿名类型时重命名字段;下面的示例将 UnitPrice
字段重命名为 Price
。
select new {p.ProductName, Price = p.UnitPrice};
集合初始值设定项
在初始化实现 IEnumerable 的集合类型和初始化使用适当的签名作为实例方法或扩展方法的 Add
时,集合初始值设定项允许指定一个或多个元素初始值设定项。 元素初始值设定项可以是简单的值、表达式或对象初始值设定项。 通过使用集合初始值设定项,无需指定多个调用;编译器将自动添加这些调用。
下面的示例演示了两个简单的集合初始值设定项:
List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };
下面的集合初始值设定项使用对象初始值设定项来初始化上一个示例中定义的 Cat
类的对象。 请注意,各个对象初始值设定项分别括在大括号中且用逗号隔开。
List<Cat> cats = new List<Cat>
{
new Cat{ Name = "Sylvester", Age=8 },
new Cat{ Name = "Whiskers", Age=2 },
new Cat{ Name = "Sasha", Age=14 }
};
如果集合的 Add
方法允许,则可以将 null 指定为集合初始值设定项中的一个元素。
List<Cat> moreCats = new List<Cat>
{
new Cat{ Name = "Furrytail", Age=5 },
new Cat{ Name = "Peaches", Age=4 },
null
};
如果集合支持读取/写入索引,可以指定索引元素。
var numbers = new Dictionary<int, string>
{
[7] = "seven",
[9] = "nine",
[13] = "thirteen"
};
前面的示例生成调用 Item[TKey] 以设置值的代码。 从 C# 6 开始,可以使用以下语法初始化字典和其他关联容器。 请注意,它使用具有多个值的对象,而不是带括号和赋值的索引器语法:
var moreNumbers = new Dictionary<int, string>
{
{19, "nineteen" },
{23, "twenty-three" },
{42, "forty-two" }
};
下例结合了对象和集合初始值设定项的概念。
1 public class InitializationSample
2 {
3 public class Cat
4 {
5 // 自动属性
6 public int Age { get; set; }
7 public string Name { get; set; }
8
9 public Cat() { }
10
11 public Cat(string name)
12 {
13 Name = name;
14 }
15 }
16
17 public static void Main()
18 {
19 Cat cat = new Cat { Age = 10, Name = "Fluffy" };
20 Cat sameCat = new Cat("Fluffy"){ Age = 10 };
21
22 List<Cat> cats = new List<Cat>
23 {
24 new Cat { Name = "Sylvester", Age = 8 },
25 new Cat { Name = "Whiskers", Age = 2 },
26 new Cat { Name = "Sasha", Age = 14 }
27 };
28
29 List<Cat> moreCats = new List<Cat>
30 {
31 new Cat { Name = "Furrytail", Age = 5 },
32 new Cat { Name = "Peaches", Age = 4 },
33 null
34 };
35
36 // 打印结果
37 System.Console.WriteLine(cat.Name);
38
39 foreach (Cat c in cats)
40 System.Console.WriteLine(c.Name);
41
42 foreach (Cat c in moreCats)
43 if (c != null)
44 System.Console.WriteLine(c.Name);
45 else
46 System.Console.WriteLine("List element has null value.");
47 }
48 // 输出:
49 //Fluffy
50 //Sylvester
51 //Whiskers
52 //Sasha
53 //Furrytail
54 //Peaches
55 //List element has null value.
56 }
下面的示例展示了实现 IEnumerable 且包含具有多个参数的 Add
方法的一个对象,它使用在列表中每项具有多个元素的集合初始值设定项,这些元素对应于 Add
方法的签名。
1 public class FullExample
2 {
3 class FormattedAddresses : IEnumerable<string>
4 {
5 private List<string> internalList = new List<string>();
6 public IEnumerator<string> GetEnumerator() => internalList.GetEnumerator();
7
8 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalList.GetEnumerator();
9
10 public void Add(string firstname, string lastname,
11 string street, string city,
12 string state, string zipcode) => internalList.Add(
13 $@"{firstname} {lastname}
14 {street}
15 {city}, {state} {zipcode}"
16 );
17 }
18
19 public static void Main()
20 {
21 FormattedAddresses addresses = new FormattedAddresses()
22 {
23 {"John", "Doe", "123 Street", "Topeka", "KS", "00000" },
24 {"Jane", "Smith", "456 Street", "Topeka", "KS", "00000" }
25 };
26
27 Console.WriteLine("Address Entries:");
28
29 foreach (string addressEntry in addresses)
30 {
31 Console.WriteLine("\r\n" + addressEntry);
32 }
33 }
34
35 /*
36 * 输出:
37
38 Address Entries:
39
40 John Doe
41 123 Street
42 Topeka, KS 00000
43
44 Jane Smith
45 456 Street
46 Topeka, KS 00000
47 */
48 }
Add
方法可使用 params
关键字来获取可变数量的自变量,如下例中所示。 此示例还演示了索引器的自定义实现,以使用索引初始化集合。
1 public class DictionaryExample
2 {
3 class RudimentaryMultiValuedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, List<TValue>>>
4 {
5 private Dictionary<TKey, List<TValue>> internalDictionary = new Dictionary<TKey, List<TValue>>();
6
7 public IEnumerator<KeyValuePair<TKey, List<TValue>>> GetEnumerator() => internalDictionary.GetEnumerator();
8
9 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalDictionary.GetEnumerator();
10
11 public List<TValue> this[TKey key]
12 {
13 get => internalDictionary[key];
14 set => Add(key, value);
15 }
16
17 public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable<TValue>)values);
18
19 public void Add(TKey key, IEnumerable<TValue> values)
20 {
21 if (!internalDictionary.TryGetValue(key, out List<TValue> storedValues))
22 internalDictionary.Add(key, storedValues = new List<TValue>());
23
24 storedValues.AddRange(values);
25 }
26 }
27
28 public static void Main()
29 {
30 RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary1
31 = new RudimentaryMultiValuedDictionary<string, string>()
32 {
33 {"Group1", "Bob", "John", "Mary" },
34 {"Group2", "Eric", "Emily", "Debbie", "Jesse" }
35 };
36 RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary2
37 = new RudimentaryMultiValuedDictionary<string, string>()
38 {
39 ["Group1"] = new List<string>() { "Bob", "John", "Mary" },
40 ["Group2"] = new List<string>() { "Eric", "Emily", "Debbie", "Jesse" }
41 };
42 RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary3
43 = new RudimentaryMultiValuedDictionary<string, string>()
44 {
45 {"Group1", new string []{ "Bob", "John", "Mary" } },
46 { "Group2", new string[]{ "Eric", "Emily", "Debbie", "Jesse" } }
47 };
48
49 Console.WriteLine("Using first multi-valued dictionary created with a collection initializer:");
50
51 foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary1)
52 {
53 Console.WriteLine($"\r\nMembers of group {group.Key}: ");
54
55 foreach (string member in group.Value)
56 {
57 Console.WriteLine(member);
58 }
59 }
60
61 Console.WriteLine("\r\nUsing second multi-valued dictionary created with a collection initializer using indexing:");
62
63 foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary2)
64 {
65 Console.WriteLine($"\r\nMembers of group {group.Key}: ");
66
67 foreach (string member in group.Value)
68 {
69 Console.WriteLine(member);
70 }
71 }
72 Console.WriteLine("\r\nUsing third multi-valued dictionary created with a collection initializer using indexing:");
73
74 foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary3)
75 {
76 Console.WriteLine($"\r\nMembers of group {group.Key}: ");
77
78 foreach (string member in group.Value)
79 {
80 Console.WriteLine(member);
81 }
82 }
83 }
84
85 /*
86 * 输出:
87
88 Using first multi-valued dictionary created with a collection initializer:
89
90 Members of group Group1:
91 Bob
92 John
93 Mary
94
95 Members of group Group2:
96 Eric
97 Emily
98 Debbie
99 Jesse
100
101 Using second multi-valued dictionary created with a collection initializer using indexing:
102
103 Members of group Group1:
104 Bob
105 John
106 Mary
107
108 Members of group Group2:
109 Eric
110 Emily
111 Debbie
112 Jesse
113
114 Using third multi-valued dictionary created with a collection initializer using indexing:
115
116 Members of group Group1:
117 Bob
118 John
119 Mary
120
121 Members of group Group2:
122 Eric
123 Emily
124 Debbie
125 Jesse
126 */
127 }