为什么集合初始化会忽略访问修饰符?

时间:2013-10-10 19:58:52

标签: c# .net access-modifiers

来自this answer的Spawing,出现了一些似乎没有意义的代码:

class Program
{
    static void Main(string[] args)
    {
        var t = new Testing
        {
            ListOfStrings =
            { 
                "hello", 
                "goodbye" 
            }
        };

        Console.ReadKey();
    }
}

public class Testing
{
    public List<string> ListOfStrings { get; private set; }

    public Testing()
    {
        ListOfStrings = new List<string>();
    }
}

乍一看,人们会认为这段代码无法编译:毕竟ListOfStrings应该有私有的setter,并且不应该以这种方式分配。

但是,此代码编译并运行正常,t.ListOfStrings已分配值。

为什么此集合初始化会忽略私有setter?

2 个答案:

答案 0 :(得分:3)

在您的示例中,您实际上并未设置属性。

C#非常聪明,知道您正在使用ICollection,可以使用Add,Remove,Clear等进行公开修改。您正在做的是相当于:

t.AddRange(new string[] { "hello", "goodbye" });

如果你真的试图这样做,那就不行了:

var t = new Testing
{
    ListOfStrings = new List<string>(),
};

修改

由于您可能想知道如何将集合公开为只读,您可以通过将其公开为IEnumerable来实现:

public class Testing
{
    private List<string> _listOfStrings;
    public IEnumerable<string> MyStrings
    {
        get
        {
            foreach (var s in _myStrings)
                yield return s;
        }
    }

    public Testing()
    {
        _listOfStrings = new List<string>();
    }
}

你也可以创建一个只读集合,但我发现这更令人困惑。如果您将其公开为IEnumerable,那么该类的消费者可以枚举这些项目,而无法添加或删除项目。

答案 1 :(得分:1)

  

为什么此集合初始化会忽略私有setter?

没有。此集合初始化语法:

    var t = new Testing
    {
        ListOfStrings =
        { 
            "hello", 
            "goodbye" 
        }
    };

实际上是由编译器转换为这样的:

var t = new Testing();
t.ListOfStrings.Add("hello");
t.ListOfStrings.Add("goodbye");

正如您所看到的,ListOfStrings实际上并未分配新值...