C#中的"const正确性"

ten*_*npn 78 c# theory const-correctness

const-correctness的要点是能够提供用户无法更改或删除的实例的视图.编译器支持这一点,指出何时从const函数中断开constness,或者尝试使用const对象的非const函数.因此,如果不复制const方法,我可以在C#中使用具有相同目的的方法吗?

我知道不变性,但这并不能真正地将容器对象转移到一个例子.

Tra*_*rap 62

我也经常遇到这个问题并最终使用接口.

我认为重要的是放弃C#是任何形式的想法,甚至是C++的演变.它们是两种不同的语言,它们的语法几乎相同.

我通常通过定义类的只读视图来表达C#中的'const correctness':

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 当然,但如果您的某个字段是List或富类型,该怎么办?您的解决方案很快变得复杂. (12认同)
  • @Trap:这就是问题的重点.返回一个内部集合是一种不好的做法,因为外部世界可以修改你的内部结构,在C++中使用const解决:你提供了一个恒定的集合视图(不能添加/删除元素,只提供一个恒定的视图元素)因此它是安全的(和一个常见的习语).无需编制接口或其他技巧来避免外部代码更改内部. (12认同)
  • 值得注意的是,`const`-ness**是设计的一部分,它声明的意图与编写外部const接口一样清晰.此外,如果必须手动处理const-interfaces,则提供const-interfaces可能是一项复杂的任务,并且可能需要写入几乎与复合类型中存在的类一样多的接口.这将我们带到你最后的感觉:'由于忘记添加const而搞砸了'.更容易习惯在各处添加`const`(开发成本很小),而不是为每个类编写只读接口. (10认同)
  • @Trap,我同意这个机制是对开发的一种帮助,其中包括检测开发人员的错误,无论是否有经验.我不同意必须编写只读接口是一个更好的解决方案.第一点是无论何时用C++编写类,都隐式定义了常量接口:成员子集声明为`const`,没有定义单独接口和需要运行时调度的额外成本.也就是说,该语言提供了一种实现编译时const接口的简单方法. (9认同)
  • 我真正喜欢C#的原因之一就是它没有像Java那样抛弃C++的所有实用功能.Java尝试用接口做所有事情,这是一场灾难.证据就在布丁中.随着时间的推移,很多功能被添加到Java中,最初被谴责为异端邪说.基于接口的设计已经占据了它的位置,但是当采用极端情况时,可能会不必要地使程序的架构复杂化.您最终会花费更多时间编写样板代码,而花费更少时间来完成有用的工作. (9认同)
  • 这不是那些有"答案"的问题之一,但我真的很喜欢这个解决方案.它很优雅,可以适应很多情况,而且写得很快. (3认同)
  • 我赞成"IReadableCustomer"作为接口的名称,而不是"IReadOnlyCustomer",因为后者在由"IReadWriteCustomer"继承时会暗示矛盾[如果接口名称的主要字符是小写的,我会使用"iMutableCustomer" ",但"IMutableCustomer"看起来太像"ImmutableCustomer"] (3认同)
  • 请记住,这只是删除只读性的一个转换 - 即“(Customer) myCustomer”。不过,如果你表现得很好并且不那样做的话,这可能是最好的解决方案:) (2认同)
  • 如果在自己的对象中包含足够大的可变对象,那么如何为包含对象提供只读接口?你会创建一个包含对象的副本吗?当你了解const引用有多强大时,这是你唯一想念的. (2认同)
  • @supercat为什么不简单地使用“ICustomer”作为可变接口的名称?我相信这遵循微软的命名模式,例如 [ICollection<T>](https://msdn.microsoft.com/en-us/library/92t2ye13(v=vs.110).aspx) 和 [IReadOnlyCollection<T> ](https://msdn.microsoft.com/en-us/library/hh881542(v=vs.110).aspx)。 (2认同)

Sam*_*Sam 28

为了获得const-craziness(或函数式编程术语中的纯粹)的好处,您需要以某种方式设计类,使它们是不可变的,就像c#的String类一样.

这种方法比仅将对象标记为只读更好,因为使用不可变类,您可以在多任务环境中轻松传递数据.

  • 但是不变性并不能真正扩展到复杂的对象,或者它是什么? (8认同)
  • 我认为,如果你的对象如此复杂以至于不可能进行不可变性,你就有了很好的重构能力. (8认同)
  • @tenpn:当完成正确时,不变性实际上非常好地扩展.真正有用的一件事是对大型不可变类型使用`Builder`类(Java和.NET定义了`StringBuilder`类,这只是一个例子). (8认同)
  • 不仅如此,但有些情况下你确实想要更改对象(对象确实发生变化!)但在大多数情况下仍然提供只读视图.不可变对象意味着无论何时需要进行更改(发生更改),您都需要创建一个除了更改之外的所有相同数据的新对象.考虑一所有学校教室的学校,学生......每次学生的出生日期和年龄变化时,你想创建一所新学校吗?或者你可以改变学生级别的年龄,房间级别的学生,也许是学校级别的学生? (3认同)
  • 我认为这是最好的一组.不可变对象的使用率很低. (2认同)

Ric*_*ich 23

我只想告诉你,许多System.Collections.Generics容器都有一个AsReadOnly方法,它会返回一个不可变的集合.

  • 即使ReadOnlyCollection <T>不是,T仍然是可变的,这仍然存在问题。 (2认同)