C#中的"常量正确性"
const正确性的重点是能够提供用户无法更改或者删除的实例的视图。编译器通过指出何时从const函数中破坏constness或者尝试使用const对象的非const函数来支持此功能。因此,无需复制const方法,是否可以在C中使用具有相同目的的方法?
我知道不变性,但这并没有真正延续到容器对象上,仅举一个例子。
解决方案
C没有这种功能。我们可以按值或者引用传递参数。引用本身是不可变的,除非我们指定ref修饰符。但是引用的数据并不是一成不变的。因此,如果要避免副作用,则需要小心。
MSDN:
传递参数
为了获得const-craziness(或者函数式编程术语的纯净)的好处,我们将需要以某种方式设计类,使其不可变,就像cis的String类一样。
这种方法比仅将对象标记为只读要好得多,因为使用不可变的类,我们可以在多任务环境中轻松传递数据。
- const关键字可用于编译时间常数,例如原始类型和字符串
- readonly关键字可用于运行时常量,例如引用类型
只读的问题在于,它仅允许引用(指针)为常数。引用(指向)的内容仍可以修改。这是棘手的部分,但是没有办法解决。实现常量对象意味着使它们不公开任何可变的方法或者属性,但这很尴尬。
另请参见有效的C#:改进C的50种特定方法(第2项建议以const方式为只读)。
我也多次遇到这个问题,最终使用接口。
我认为重要的是,放弃任何形式的Cis,甚至C ++的演变。它们是两种共享几乎相同语法的不同语言。
我通常在C中通过定义类的只读视图来表达"常量正确性":
public interface IReadOnlyCustomer { String Name { get; } int Age { get; } } public class Customer : IReadOnlyCustomer { private string m_name; private int m_age; public string Name { get { return m_name; } set { m_name = value; } } public int Age { get { return m_age; } set { m_age = value; } } }
接口是答案,并且实际上比C ++中的" const"更强大。 const是一种"一刀切"的解决方案,其中的问题是将" const"定义为"不设置成员或者调用某些设置成员的东西"。在许多情况下,这是保持一致性的好捷径,但并非所有情况都如此。例如,考虑一个函数,该函数根据某些成员计算值,但也缓存结果。在C ++中,这被认为是非const,尽管从用户的角度来看,它本质上是const。
接口使我们可以更灵活地定义要从类中提供的功能的特定子集。想要保持不变?只需提供没有任何变异方法的接口即可。是否要允许设置某些东西,而不允许其他东西?仅提供带有这些方法的接口。
我只是想为我们指出,许多System.Collections.Generics容器都有一个AsReadOnly方法,它将为我们提供不可变的集合。
与其他一些人达成一致的看法是,使用在构造函数中初始化的只读字段创建不可变对象。
public class Customer { private readonly string m_name; private readonly int m_age; public Customer(string name, int age) { m_name = name; m_age = age; } public string Name { get { return m_name; } } public int Age { get { return m_age; } } }
或者,我们也可以在属性上添加访问范围,即public get和protected set?
public class Customer { private string m_name; private int m_age; protected Customer() {} public Customer(string name, int age) { m_name = name; m_age = age; } public string Name { get { return m_name; } protected set { m_name = value; } } public int Age { get { return m_age; } protected set { m_age = value; } } }