属性 初始化不为 List<T> 调用 set
Property initialization does not call set for List<T>
我在检查 class 的属性的代码覆盖率时发现了一个场景。当 属性 的类型为 List< T >,并且使用了初始值设定项时,似乎没有调用 set 方法。对于其他类型,例如字符串和整数,情况并非如此。代码覆盖率不显示 set 调用,也不命中 set 中的断点。
示例class:
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; }
}
当使用初始化器时,如下所示,Text 上的 set 方法被调用,并在代码覆盖率中注册,但 Items 上的 set 方法没有,我想知道为什么:
var arrange = new ContainerClass
{
Text = "value",
Items = { new Item() }
};
编辑:我要指出的是列表已正确分配,并且可以对其进行测试,但它似乎绕过了实际的设置方法。
有趣的是,当我指定新列表时,它确实被调用了:
var arrange = new ContainerClass
{
Items = new List<Item> { new Item() }
};
您可以执行以下任一操作:
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} }
};
When using an initializer, like below, the set method on Text is called, and registers in code coverage, but the set method on Items does not, and I am wondering why:
那是因为在调用集合初始化程序时,Items 列表实际上并未被初始化。来自规范的第 7.6.10.2 节:
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the field or property, the elements given in the initializer are added to the collection referenced by the field or property.
这意味着集合初始化器假设集合已经被实例化(即使在对象初始化器之外也是如此)。请记住,集合初始化程序只不过是一系列 .Add()
调用。
为了使您的代码 运行 没有错误,项目必须已经初始化。这可能发生在 属性 声明本身(假设它是一个自动实现的 属性):
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 永远不会被 Items 调用的说法,它很可能是在 属性 声明(或支持字段,如果它实际上不是自动实现的 属性).如果它在构造函数中初始化,setter 仍然会被调用。
您的第二个示例导致 setter 被调用,因为您确实正在为那里的项目分配一个新列表。
我在检查 class 的属性的代码覆盖率时发现了一个场景。当 属性 的类型为 List< T >,并且使用了初始值设定项时,似乎没有调用 set 方法。对于其他类型,例如字符串和整数,情况并非如此。代码覆盖率不显示 set 调用,也不命中 set 中的断点。
示例class:
public class ContainerClass
{
public string Text { get; set; }
public List<Item> Items { get; set; }
}
当使用初始化器时,如下所示,Text 上的 set 方法被调用,并在代码覆盖率中注册,但 Items 上的 set 方法没有,我想知道为什么:
var arrange = new ContainerClass
{
Text = "value",
Items = { new Item() }
};
编辑:我要指出的是列表已正确分配,并且可以对其进行测试,但它似乎绕过了实际的设置方法。
有趣的是,当我指定新列表时,它确实被调用了:
var arrange = new ContainerClass
{
Items = new List<Item> { new Item() }
};
您可以执行以下任一操作:
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} }
};
When using an initializer, like below, the set method on Text is called, and registers in code coverage, but the set method on Items does not, and I am wondering why:
那是因为在调用集合初始化程序时,Items 列表实际上并未被初始化。来自规范的第 7.6.10.2 节:
A member initializer that specifies a collection initializer after the equals sign is an initialization of an embedded collection. Instead of assigning a new collection to the field or property, the elements given in the initializer are added to the collection referenced by the field or property.
这意味着集合初始化器假设集合已经被实例化(即使在对象初始化器之外也是如此)。请记住,集合初始化程序只不过是一系列 .Add()
调用。
为了使您的代码 运行 没有错误,项目必须已经初始化。这可能发生在 属性 声明本身(假设它是一个自动实现的 属性):
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 永远不会被 Items 调用的说法,它很可能是在 属性 声明(或支持字段,如果它实际上不是自动实现的 属性).如果它在构造函数中初始化,setter 仍然会被调用。
您的第二个示例导致 setter 被调用,因为您确实正在为那里的项目分配一个新列表。