Tim
Tim

Reputation: 45

Cannot implement interface member using derived type

Lets assume I've got a class Called StreetModel that implements an interface called IStreetModel:

public class StreetModel: IStreetModel {
    // Properties go here
}

Said IStreetModel looks like so:

public interface IStreetModel {
    // Properties go here
}

Now, say I have another interface called ILocationModel that contains a property of type IStreetModel:

public interface ILocationModel {
    IStreetModel Street { get; }
}

And this ILocationModel interface is implemented by a class called LocationModel:

public class LocationModel: ILocationModel {
    public StreetModel Street { get; } // This is where my query is
}

My Question: Within LocationModel, why can't I implement StreetModel even though it implements IStreetModel. Why does the compiler want IStreetModel specifically? It's confusing for me because in almost every other scenario within my program (except for collections) I can interchange usage of the two. Why not here?

Error Message:

'LocationModel' does not implement interface member 'ILocationModel.Street'. 'LocationModel.Street' cannot implement 'ILocationModel.Street' because it does not have the matching return type of 'IStreetModel'.

Upvotes: 1

Views: 580

Answers (1)

Matthew Watson
Matthew Watson

Reputation: 109802

The answer to your actual question ("why doesn't it compile?") is: The c# language requires that a return type for an implemented interface member matches exactly. That's the way the language was designed.

This was fixed by c# 9 in some cases, but not for interface implementations. See the section following The remainder of the draft specification below proposes a further extension to covariant returns of interface methods to be considered later in this documentation.

In the meantime, a possible workaround is to make your ILocationModel generic like so:

public interface IStreetModel
{
    // Properties go here
}

public interface ILocationModel<out T> where T: IStreetModel
{
    T Street { get; }
}

public class StreetModel : IStreetModel
{
    // Properties go here
}

public class LocationModel : ILocationModel<StreetModel>
{
    public StreetModel Street { get; } // This is where my query is
}

Of course the most obvious solution is simply to declare the return type of LocationModel.Street as IStreetModel.

Another alternative is to use explicit interface implementation, like so:

public class LocationModel : ILocationModel
{
    public StreetModel Street { get; } // This is where my query is

    IStreetModel ILocationModel.Street => Street;
}

Upvotes: 5

Related Questions