Search code examples
c#setter

C# Setter behavior difference in interface and interface with inheritance


I am currently learning C# and I have observed behavior that I cannot explain when I was playing around.

Given this interface:

using System;

namespace LearnInterfaces
{
  interface IAutomobile
  {
    string LicensePlate { get; }
    double Speed { get; }
    int Wheels { get; }
    void Honk();
  }
}

I implement the class like so :

using System;

namespace LearnInterfaces
{
  class Sedan : IAutomobile
  {
    public Sedan(double speed, int wheels){
      this.Speed = speed;
      this.LicensePlate = Tools.GenerateLicensePlate();
      this.Wheels = wheels;
    }

    public string LicensePlate
    { get; }

    public double Speed
    { get; }

    public int Wheels
    { get; }

    publc void Honk(){.....};
    
  }
}

This is fine, and I can instantiate the Sedan in my main program.

However, when it comes to inheritance + interface, this behavior is no longer ok:

If I decided to add a new base class and make Sedan inherit from it:

class Vehicle
{
    public string LicensePlate
    { get; }

    public double Speed
    { get; }

    public int Wheels
    { get; }

    
    public void Honk()
    {
      Console.WriteLine("HONK!");
    }

}

Changed so that Sedan inherit from it:

  class Sedan : Vehicle, IAutomobile
  {
    public Sedan(double speed)
    {
      Speed = speed;
      LicensePlate = Tools.GenerateLicensePlate();
      Wheels = 4;
    }
    
  }

Now if I try to instantiate from my main program, I get Property or indexer 'Vehicle.Speed' cannot be assigned to -- it is read only. The same error happens for every property in the class.

Why do I need a setter now when I make Sedan inherit from a base class? In my understanding, the Sedan will also inherit the getter; so instantiate it with constructor should be ok (just like previous example where it simply implements the interface).


Solution

  • Why do I need a setter now?

    Because a get-only auto-property can only be assigned in the constructor of the enclosing class.

    From the language spec:

    Just like a readonly field, a getter-only auto-property can also be assigned to in the body of a constructor of the enclosing class. Such an assignment assigns directly to the readonly backing field of the property.

    So essentially you are assigning to the backing field of the property, which is readonly. If you read about the behaviour of readonly, the reason for this restriction is even clearer:

    Direct assignments to readonly fields can only occur as part of that declaration or in an instance constructor or static constructor in the same class.

    Sedan is not the enclosing class of LicensePlate, Speed and Wheels etc, so you can't set them in Sedan's constructor.