我在检查类属性的代码覆盖时发现了一个场景。当属性类型为List<使用T>和初始化器,似乎没有调用set方法。对于其他类型,例如字符串和整数,情况并非如此。代码覆盖率不显示set调用,set中的断点也不会被命中。
示例类:
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; }
}
当使用初始化程序时,如下所示,调用Text上的set方法,并在代码覆盖中注册,但是item上的set方法没有,我想知道原因:
var arrange = new ContainerClass
{
Text = "value",
Items = { new Item() }
};
编辑:我会指出列表已正确分配,可以进行测试,但它似乎绕过实际的set方法。
有趣的是,当我指定新列表时,它会被调用:
var arrange = new ContainerClass
{
Items = new List<Item> { new Item() }
};
答案 0 :(得分:3)
当使用初始化程序时,如下所示,调用Text上的set方法,并在代码覆盖中注册,但是item上的set方法没有,我想知道原因:
那是因为在调用集合初始值设定项时实际上没有初始化Items列表。来自规范的第7.6.10.2节:
在等号后面指定集合初始值设定项的成员初始值设定项是嵌入式集合的初始化。而不是将新集合分配给字段或属性,初始化程序中给出的元素将添加到字段或属性引用的集合中。
这意味着集合初始化程序假定集合已经被实例化(即使在对象初始化程序之外也是如此)。请记住,集合初始值设定项只不过是一系列.Add()
次调用。
为了让您的代码无错误地运行,必须已经初始化了Items。这可能发生在财产声明本身(假设它是一个自动实现的属性):
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; } = new List<Item>();
}
或者在构造函数中(您还没有显示):
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; }
public ContainerClass()
{
Items = new List<Item>();
}
}
否则,当程序尝试评估集合初始值设定项时,您的代码将抛出NullReferenceException。
根据你的声明,setter永远不会被调用,它很可能是在属性声明(或支持字段,如果它实际上不是自动实现的属性)中初始化的。如果它已在构造函数中初始化,则仍然会调用setter。
你的第二个例子导致调用setter,因为你确实为那里的Items分配了一个新的列表。
答案 1 :(得分:0)
您可以这样做:
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; }
public ContainerClass()
{
Items = new List<Item>();
}
}
然后:
var arrange = new ContainerClass
{
Text = "SomeValue"
};
arrange.Items.Add(new Item(){Prop=Value});
或者,如果你没有按照规定使用构造函数,你可以像这样初始化一个列表:
var arrange = new ContainerClass
{
Items = new List<Item>(){ new Item(){Prop=Value} }
};