Search code examples
c#inheritanceinterfacepropertiesreadonly

Including setter property on child class that inherited the property from a read-only interface


Thought this was a duplicate question but other questions are all slightly different.

I have some parent interfaces and inheriting classes like this:

public interface IPerson 
{
  IPersonData PersonData {get;}
  //other stuff
}

public interface IPersonData
{
  public String Name {get;}
  //other stuff
}

public class Person : IPerson
{//need to implement IPersonData
  IPersonData PersonData {get;set;} = new PersonData();
  //other stuff
  PersonData.Name = "JohnDoe";//compiler error somewhere in a method
}

public class PersonData : IPersonData
{//need to implement IPersondata
  public String Name {get;set;}
  //other stuff
}

So my goal as you can see is to implement the IPerson interface while also being able to write to the Name property of the IPersonData (instantiated as a PersonData). As the code is written here, if I tried to do PersonData.Name = "JohnDoe" the compiler will throw an error because the property is apparently read-only. If I try to change IPersonData to be PersonData pd = New PersonData, then I am obviously no longer implementing the interface requirement.

I have to do this because these are interfaces that are required and are not written or controlled by me. When these interfaces were written originally they were done in a time where they probably didn't have auto-fielded properties.

What I know is that I could implement a field behind it and have the program write to the field when I need to write, and the property can reference the field. However, I feel this is probably not the "correct" way to do things in c# in 2021 where everything is a property and it adds lines of code I feel are probably not needed.

So is there a more "correct" way to do this if I cannot rewrite the interface, or is adding a field the only thing that can be done?

Before someone says "this question has been answered by such and such before" please make sure they are not referring to an INTERFACE inheriting another interface, where that actually does work. Apparently, this issue only exists when a concrete class inherits an interface.


Solution

  • You can achieve your goal by explicitly implementing the interface. In this example, my implementation makes use of the existing property (adjusted to type PersonData):

    public class Person : IPerson
    {//need to implement IPersonData
        public PersonData PersonData { get; set; } = new PersonData();
        IPersonData IPerson.PersonData => PersonData;
        //other stuff
    }
    

    The code

    Person fred = new Person(); 
    fred.PersonData.Name = "Fred";  
    Console.WriteLine(fred.PersonData.Name);
    

    outputs

    Fred

    The class now fulfills the contract of IPerson and provides additional functionality not defined in a contract (interface).