富类型C#中的常量正确性 来自C++背景,试图学习C语言,我遇到的最令人沮丧的语言遗漏之一是等同于 const Time>p>

富类型C#中的常量正确性 来自C++背景,试图学习C语言,我遇到的最令人沮丧的语言遗漏之一是等同于 const Time>p>,c#,.net,constants,const-correctness,readonly,C#,.net,Constants,Const Correctness,Readonly,因此,我一直在尝试解决一个模式,我可以用它来实现C#中常量的正确性 有一个有趣的建议:为所有类型创建一个只读接口。但是正如Matt Cruikshank在评论中指出的那样,如果您的类具有集合或其他丰富类型,那么这将成为一个问题。特别是如果您无法控制该类型,并且无法使其实现只读接口 是否存在能够处理丰富类型和集合的模式或解决方案,或者我们是被迫在C#中进行复制的?完全放弃C中的常量正确性更好吗?你能在C中获得不变性吗?当然,如果你为它设计的话。您可以使用接口等进行创造性的操作,只公开属性的get,

因此,我一直在尝试解决一个模式,我可以用它来实现C#中常量的正确性

有一个有趣的建议:为所有类型创建一个只读接口。但是正如Matt Cruikshank在评论中指出的那样,如果您的类具有集合或其他丰富类型,那么这将成为一个问题。特别是如果您无法控制该类型,并且无法使其实现只读接口


是否存在能够处理丰富类型和集合的模式或解决方案,或者我们是被迫在C#中进行复制的?完全放弃C中的常量正确性更好吗?

你能在C中获得不变性吗?当然,如果你为它设计的话。您可以使用接口等进行创造性的操作,只公开属性的
get
,而不公开任何可变方法

这句话,记住,没有什么可以防止狡猾的用户将它重新转换成实际类型(当然,同样可以说是C++,你可以抛弃本质)。 收藏也是如此。即使返回ReadOnlyCollection(它可以防止集合本身的行为发生变化),集合中的数据仍然是可变的(当然,只要类型允许)

所以我恐怕这里没有简单的答案。没有“翻转开关”const给你C++所做的。 这真的取决于你,你可以:

  • 将类型设计为不可变的,并返回迭代器(或其他只读序列),而不是可变集合
  • 每次都要归还新的副本,这样如果他们修改它们就没什么大不了的了
  • 只需返回实际数据,并将篡改行为保留为“未定义”
  • 等等
后者是像
Dictionary
这样的集合所做的。没有任何东西说你不能使密钥类型变为可变类型(但如果你这样做了,那就糟了),而且MSDN非常清楚,如果你以散列代码更改的方式更改密钥,那么它将由你自己决定

对于我自己的工作,我倾向于保持简单,除非实际上有一个很大的担忧,我的课程可能会被改变,从而导致副作用。例如,如果我将web服务结果存储在缓存中,我将返回缓存项的副本,以便用户修改结果时不会无意中修改缓存值


所以,长话短说,我不会担心返回的每种类型的const正确性,这太过分了。我只担心您返回的内容,如果更改,可能会对其他用户产生副作用

我建议阅读Eric Lippert的一系列博客(链接显示了所有标记为不可变的帖子-寻找那些在C#中标题为
不可变的帖子),其中开发了不可变的集合类型。如果你真的希望某个类型是不可变的,你非常需要这样设计它。当然有
ReadOnlyCollection
之类的,但是它们有点平淡无奇,因为它们仍然有变异的方法,调用时只抛出。但是,是的,我也渴望有一个C++-ish
const
参考……我已经编写C#多年了,我还没有看到一个场景,其中
const
关键字可以让我免于犯错误。在C++中,<>代码> const 的好处被过分夸大了。在C语言中使用C++编程,而不是向后弯曲,尝试C语言模型来编程。几年后,我怀疑你会不会想回去。@Stargazer712:我不得不说,我不同意过度夸大const-correction的好处。当然,做对是一件痛苦的事,但在一个好的设计中是值得的。也就是说,我知道很多人也有你的感受,所以这只是我的0美元。02@JeffYates:我想说,仅仅为了const正确性而改装模型可能不值得,但是如果你从一开始就采用const正确的设计,它可以防止一些粗心或业余的错误。很好的总结和很好的建议,请记住,没有任何东西可以阻止狡猾的用户将其转换回实际类型
。这太荒谬了。没有任何东西可以阻止用户访问另一个对象的私有字段;只要使用反射。这并不意味着不应该有
private
变量。@user我认为这一点都不可笑。OP询问是否可以制作一个类型
const
,答案并不简单。因此,重要的是让他们知道,虽然这是一种简单的方法,但并不是一种保证。
ISomeReadOnlyInterface readOnly = new SomeFullObject();

// hah, take that read-only interface!
((SomeFullObject)readOnly).SomeMutatingMethod();