属性初始化不调用List< T>的集合. [英] Property initialization does not call set for List<T>

查看:57
本文介绍了属性初始化不调用List< T>的集合.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在检查类属性的代码覆盖率时发现了一个场景.当该属性的类型为List<T>,并使用初始化程序,似乎没有调用set方法.对于其他类型,例如字符串和整数,则不是这样.代码覆盖率不会显示set调用,set中的断点也不会命中.

I've got a scenario I discovered when checking code coverage on a class's properties. When the property is of type List< T >, and an initializer is used, the set method doesn't appear to be called. This isn't true of other types, like strings and ints. Code coverage doesn't show the set call, nor does a breakpoint in set get hit.

示例类:

public class ContainerClass
{
    public string Text { get; set; }
    public List<Item> Items { get; set; }
}

使用初始化程序时,如下所示,将调用Text上的set方法,并在代码覆盖率中注册,但是Items上的set方法却没有,我想知道为什么:

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:

var arrange = new ContainerClass
{
    Text = "value",
    Items = { new Item() }
};

我要指出的是,该列表已正确分配,可以针对该列表进行测试,但它似乎与实际的set方法有关.

I would point out that the list is correctly assigned, and can be tested against, but it appears to go around the actual set method.

有趣的是,当我指定新列表时,它确实会被调用:

Interestingly, when I specify the new list, it does get called:

var arrange = new ContainerClass
{
    Items = new List<Item> { new Item() }
};

推荐答案

使用初始化程序时,如下所示,将调用Text上的set方法,并在代码覆盖率中注册,但是Items上的set方法却没有,我想知道为什么:

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节:

That's because the Items list is not actually being initialized at the time the collection initializer is called. From section 7.6.10.2 of the spec:

在等号后指定集合初始值设定项的成员初始值设定项是嵌入式集合的初始化.不必为字段或属性分配新的集合,而是将初始化器中给定的元素添加到由字段或属性引用的集合中.

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()调用.

This means that the collection initializer assumes that the collection has already been instantiated (which is true even outside of an object initializer). Remember that a collection initializer is nothing more than a series of .Add() calls.

为了使您的代码无错误运行,必须已初始化项目.这可能发生在属性声明本身中(假设它是一个自动实现的属性):

In order for your code to run without errors, Items must already have been initialized. This could have happened either in the property declaration itself (assuming it's an auto-implemented property):

public class ContainerClass
{
    public string Text { get; set; }
    public List<Item> Items { get; set; } = new List<Item>();
}

或在构造函数中(您未显示):

Or in the constructor (which you haven't shown):

public class ContainerClass
{
    public string Text { get; set; }
    public List<Item> Items { get; set; }

    public ContainerClass()
    {
        Items = new List<Item>();
    }
}

否则,当程序尝试评估集合初始化程序时,您的代码将引发NullReferenceException.

Otherwise, your code will throw a NullReferenceException as the program tries to evaluate the collection initializer.

根据您的声明,即setter永远不会被要求调用Items,很可能已在属性声明(或后备字段,如果它实际上不是自动实现的属性)中对其进行了初始化.如果在构造函数中对其进行了初始化,则将仍然会调用setter.

Based on your statement that the setter never gets called for Items, it's likely it was initialized in the property declaration (or the backing field, if it's not actually an auto-implemented property). Had it been initialized in the constructor the setter would still have been called.

您的第二个示例将导致调用setter,因为您确实是在为那里的Items分配一个新列表.

Your second example results in the setter being called because you are indeed assigning a new list to Items there.

这篇关于属性初始化不调用List&lt; T&gt;的集合.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆