为什么这个字段被声明为私有和只读?

36
在以下代码中:
public class MovieRepository : IMovieRepository
{
    private readonly IHtmlDownloader _downloader;

    public MovieRepository(IHtmlDownloader downloader)
    {
        _downloader = downloader;
    }

    public Movie FindMovieById(string id)
    {
        var idUri = ...build URI...;

        var html = _downloader.DownloadHtml(idUri);

        return ...parse ID HTML...;
    }

    public Movie FindMovieByTitle(string title)
    {
        var titleUri = ...build URI...;

        var html = _downloader.DownloadHtml(titleUri);

        return ...parse title HTML...;
    }
}

我请求有人帮我审查代码, 然后有人提出了这种方法。我的问题是为什么IHtmlDownloader变量是只读的?

3个回答

64
如果一个字段是私有的且带有readonly修饰符,那么它的好处在于初始化后无法从该类的其他部分意外更改它。 readonly修饰符确保字段只能在初始化或其类构造函数中赋值。
如果某个功能在初始化后不应更改,则始终使用可用的语言结构来强制执行这一点是很好的实践。
另外,C# 9引入了init 访问器方法,用于属性,表示属性值只能在对象构造期间设置,例如:
class InitExample
{
     private double _seconds;

     public double Seconds
     {
         get { return _seconds; }
         init { _seconds = value; }
     }
}

3
Bingo。如果它是只读的,它只能在对象初始化或构造函数中设置。这不是必需的,但代码质量的一部分是限制错误可能发生的范围。 - Cylon Cat
3
构造后数值固定,编译器和JIT编译器可以实现一些优化,因此有一个额外的好处。 - Jesse C. Slicer
@Adam:那篇文章中的测试过于简单。编译器完全可以分析整个程序,甚至从未调用GetValue#()函数。需要查看IL代码才能知道即使是最坏情况(普通int)也已被完全优化掉了。 - Eric J.
1
@Adam:不,我上一次认真研究编译器优化应该是10年前了(而且10年前的编译器可以优化掉所有这些调用)。对于大多数应用程序来说,现在很少有必要进行这样的优化。硬件已经足够快,可以处理许多事情,有些需要极速性能的东西(例如游戏和现在更广泛的数值计算类别,由于CUDA/OpenCL)已经有专门的硬件了,... - Eric J.
那么在这种情况下,“private readonly”和“public readonly”完全一样,对吗?那么为什么需要“private”或“public”部分呢? - aldo
显示剩余4条评论

7

这样可以确保在构造函数执行后不会更改_downloader的值。标记为readonly的字段只能在类的构造函数中被赋值。


2

只读字段用于模拟在初始化后不应更改的数据。您可以通过在声明时使用初始化程序或在构造函数中分配值来为只读字段赋值,但此后您无法更改它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接