36

In the following code:

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...;
    }
}

I asked for something to review my code, and someone suggested this approach. My question is why is the IHtmlDownloader variable readonly?

Community
  • 1
  • 1
Sergio Tapia
  • 40,006
  • 76
  • 183
  • 254

3 Answers3

63

If it's private and readonly, the benefit is that you can't inadvertently change it from another part of that class after it is initialized. The readonly modifier ensures the field can only be given a value during its initialization or in its class constructor.

If something functionally should not change after initialization, it's always good practice to use available language constructs to enforce that.

On a related note, C# 9 introduces the init accessor method for properties, which indicates the property value can only be set during object construction, e.g.:

class InitExample
{
     private double _seconds;

     public double Seconds
     {
         get { return _seconds; }
         init { _seconds = value; }
     }
}
Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • 3
    Bingo. If it's readonly, it can only be set either by object initialization, or in the constructor. It's not necessary, but part of code quality is limiting the scope in which an error can occur. – Cylon Cat Jun 13 '10 at 19:25
  • Eric's answer was good but didn't make sense until Cylon said that you could only change a readonly field in the initialization and constructor. Thanks guys! – Sergio Tapia Jun 13 '10 at 19:27
  • 3
    There is an added benefit in that the compiler and the JITter can effect certain optimizations knowing the value will be fixed after construction. – Jesse C. Slicer Jun 13 '10 at 19:29
  • @Sergio: Good point, I updated the answer to make that clear. – Eric J. Jun 13 '10 at 19:30
  • +1 for advice on language constructs - I must have seen hundreds of fields that should be readonly but aren't enforced. @Jesse C. Slicer this article seems to suggest no benefit: http://dotnetperls.com/readonly-field – Adam Houldsworth Jun 13 '10 at 19:31
  • @Adam: The tests in that article are too simplistic. It's entirely possible that the compiler can analyze the entire program and never even call the GetValue#() functions. A look at the IL code would be needed to know if even the worst-case (regular int) has not been entirely optimized away. – Eric J. Jun 13 '10 at 19:40
  • True enough. Do you have any links covering this JIT optimisation? I'm curious - don't tend to concern myself with them too much :) – Adam Houldsworth Jun 13 '10 at 19:57
  • 1
    @Adam: No, the last time I seriously looked at compiler optimizations was maybe 10 years ago (and 10 year old compilers could optimize out all of those calls). These days, there's little point to it for most apps. The hardware is "fast enough" for many things, some things that require breakneck performance (e.g. games and now broader classes of numerical computing thanks to CUDA/OpenCL) have dedicated hardware, ... – Eric J. Jun 13 '10 at 20:25
  • So in this case, "private readonly" does exactly the same as "public readonly" right? So why the need for the "private" or "public" part? – aldo Mar 16 '22 at 13:35
7

This ensures that the value of _downloader will not be changed after the constructor was executed. Fields marked as readonly can only be assigned a value from within the constructor(s) of a class.

M4N
  • 94,805
  • 45
  • 217
  • 260
2

A readonly field is useful for modelling data that should not change after it has been initialized. You can assign a value to a readonly field by using a initializer when you declare it or in a constructor, but thereafter you cannot change it.