Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding setter to inherited read-only property in C# interface

I have an interface that declares some properties (shortened to Id only in the example) with only a get method. Classes implementing this interface do not have to provide a public setter for this property:

public interface IMetadataColumns
{
    Int32 Id { get; }
}

Now I need another interface with the same properties, but now they must all be writable as well. So I added a new interface inheriting from the old one where each property also has a setter:

public interface IMetadataColumnsWritable : IMetadataColumns
{
    Int32 Id { get; set; }
}

Visual Studio now underlines this and warns me to use the new keyword if hiding the old properties was intended.


What shall I do now? I have classes implementing the IMetadataColumns interface which need some of the properties to be read-only, but I also have other classes where exactly those same properties must be writable as well.

I guess hiding a property sounds somehow not like the way to go...

like image 608
Byte Commander Avatar asked Apr 28 '16 07:04

Byte Commander


2 Answers

When interfaces are involved, the new keyword doesn't mean you are hiding the property in the same sense as with classes.

Your class implementing IMetadataColumnsWritable will only have one Id, regardless of whether you cast it to the base IMetadataColumns interface or not (unless you add an explicit implementation for the readonly property - but this is not needed and would only allow for errors in this case).

In other words, you might have:

// this interface is public, and it allows everyone to read the Id
public interface IMetadataColumns
{
    int Id { get; }
}

// this one is writeable, but it's internal
internal interface IMetadataColumnsWritable : IMetadataColumns
{
    // we need to use 'new' here, but this doesn't mean
    // you will end up with two getters
    new int Id { get; set; }
}

// internal implementation is writeable, but you can pass it 
// to other assemblies through the readonly IMetadataColumns 
// interface
internal class MetadataColumns : IMetadataColumnsWritable
{
    public int Id { get; set; }
}

So, unless you explicitly implement the readonly property as a separate one, you will have only a single property, whichever interface you use to access it:

var columns = new MetadataColumns { Id = 5 };

var x = (columns as IMetadataColumns).Id;
var y = (columns as IMetadataColumnsWritable).Id;

Debug.Assert(x == y);

Hiding a member inside the class using the new keyword, on the other hand, is what I would not recommend in most cases, because it basically creates a completely new member, which just happens to be called the same as a different member in the base class.

like image 198
Groo Avatar answered Sep 17 '22 12:09

Groo


You should indeed use the new keyword here. In your class implementation, you have to implement both properties (since you are not really hiding the property). If they have different return types, at least one of them has to be implemented explicitly.

public class X : IMetadataColumnsWritable
{
    public int Id
    {
        get;
        set;
    }

    // only necessary if you have to differentiate on the implementation.
    int IMetadataColumns.Id
    {
        get
        {
            return this.Id; // this will call the public `Id` property
        }
    }
}
like image 26
Patrick Hofman Avatar answered Sep 17 '22 12:09

Patrick Hofman