C# - 在引用类型上使用带有公共getter的私有setter

时间:2018-04-27 08:30:20

标签: c# properties encapsulation getter-setter reference-type

考虑以下使用公共getter和私有setter的短代码示例:

public class Foo        
{
    public class Bar
    {
        ...
    }

    public Bar fooBar { get; private set; }
    public int valueType { get; private set; }
}

我想确保只能从Foo类内部写入类成员。这适用于上面示例中的valueType等值类型。但是嵌套类fooBar之类的引用类型如何表现?

我可以使用公共getter返回的引用来操纵我的私有成员吗?

1 个答案:

答案 0 :(得分:6)

如果你所指的类型是可变的,那么是的,任何引用“容器”的人都可以获取引用然后改变对象。例如:

using System;
using System.Collections.Generic;

class Container
{
    public List<string> List { get; private set; }
        = new List<string>();
}

class Program
{
    static void Main()
    {
        var container = new Container();
        var list = container.List;
        Console.WriteLine(list.Count); //0

        container.List.Add("foo");
        Console.WriteLine(list.Count); // 1        
    }
}

此处List<string>正在Container之外发生变异。避免这种情况的一个选择是对可变数据使用只读视图:

using System;
using System.Collections.Generic;

class Container
{
    private readonly List<string> list = new List<string>();

    public IReadOnlyList<string> ListView { get; }

    public Container()
    {
        ListView = list.AsReadOnly();
    }

    public void AddItem(string item)
    {
        list.Add(item);
    }
}

class Program
{
    static void Main()
    {
        var container = new Container();
        Console.WriteLine(container.ListView.Count); //0

        // container.ListView.Add("foo"); // Compile-time error

        container.AddItem("foo");
        Console.WriteLine(container.ListView.Count); // 1        
    }
}

请注意,您不应该直接从属性返回列表,即使编译时类型为IReadOnlyList<T> - 因为然后调用者只能转回List<T>并进行变异。 List<T>.AsReadOnly()在列表周围返回一个真正只读的包装器对象,因此调用者实际上无法改变它。