如何使列表属性在对象初始值设定项中可写,但在其他地方只读



考虑以下未编译的代码片段。

class Class
{
public double Value { get; set; }
public int Frequency { get; set; }
}
class BoxAndWhisker
{
private readonly List<Class> _classes = new List<Class>();
public BoxAndWhisker()
{
Classes = _classes.AsReadOnly();
}
public IReadOnlyList<Class> Classes { get; } 
}
class Program
{
static void Main(string[] args)
{
BoxAndWhisker baw = new BoxAndWhisker
{
Classes =
{
new Class{ Value=1,Frequency=20},
new Class{Value=2,Frequency=10}
}
};
}
}

我希望属性Classesbaw安装后立即只读。如何做到这一点?换句话说,Classes在对象初始值设定项中必须是可写的,但在其他地方必须是只读的。

编辑

比起参数化构造函数,我更喜欢对象初始化器。

为什么不通过构造函数传递Classes?例如

class BoxAndWhisker {
public BoxAndWhisker(params Class[] items) {
Classes = null != items
? new List<Class>(items).AsReadOnly()
: throw new ArgumentNullException(nameof(items));
}
public IReadOnlyList<Class> Classes { get; }
}

然后

static void Main(string[] args) 
{
BoxAndWhisker baw = new BoxAndWhisker(
new Class { Value = 1, Frequency = 20 },
new Class { Value = 2, Frequency = 10 }
);
...
}

删除

set;

从内的属性

并使类具有一个构造函数,该构造函数设置属性的初始值,因此不能覆盖/更改

与属性值赋值相比,C#中的"对象初始值设定项"语法没有语义差异。

你可以在文档中阅读:

对象初始化器语法允许您创建一个实例,然后将新创建的对象及其分配的属性分配给分配中的变量。

因此:

var foo = new Bar { Baz = "baz" };

完全等同于

var temp = new Bar();
temp.Baz = "baz";
var foo = temp;

因此,您不能以自己想要的方式限制属性分配。唯一的解决方案是使用其他答案中提出的构造函数。

IList<Class>实例传递给BoxAndWhisker构造函数,并维护支持IReadOnlyList<Class>的属性

class BoxAndWhisker
{
public BoxAndWhisker(IList<Class> classes)
{
if (classes == null)
throw new ArgumentNullException(nameof(classes));
Classes = new ReadOnlyCollection<Class>(classes);
}
public IReadOnlyList<Class> Classes { get; }
}

的使用示例

BoxAndWhisker baw = new BoxAndWhisker(new List<Class>
{
new Class {Value = 1, Frequency = 20},
new Class {Value = 2, Frequency = 10}
});

相关内容

最新更新