jangix
jangix

Reputation: 99

Implement interface using derived types of the types defined in the interface - why can't you do it?

I have these interfaces:

public interface IService
{
    public interface IRequest { }

    void Do(IRequest request);  
}

Why is this implementation incorrect?

public class Service : IService  //Error: CS0535
{
    public class Request : IService.IRequest { }

    public void Do(Request request) { }
}

Upvotes: 0

Views: 212

Answers (2)

jangix
jangix

Reputation: 99

It's not possible implement an interface by specifying derived types instead of the types that the interface defines. Otherwise, a restriction not foreseen by the original meaning of the interface would be imposed.

All types defined in the interface must match exactly in their implementations (C#9 allows methods to return a more derived type, because that's safe).

Thanks to @canton7, @Tholdrim and @Mathias R. Jessen, for helping me come to this conclusion.

Upvotes: -1

Tholdrim
Tholdrim

Reputation: 31

This is because the interface requires a method with the signature Do(IRequest request) and you provide Do(Request request) in your implementation instead.

I think this will become clearer when we expand your example with the following code:

public class Request2 : IService.IRequest { }

And then we will try to perform the following:

var service = new Service();
var request = new Service.Request();
var request2 = new Request2();

service.Do(request); // OK
service.Do(request2); // Nope

Compare it with that:

IService service = AnyKindOfServiceResolver.Resolve<IService>();
var request = new Service.Request();
var request2 = new Request2();

service.Do(request); // OK
service.Do(request2); // OK

This difference is what makes your code unable to compile successfully. It also shows what is required of each class that is an implementation of the IService interface.

Edit: Looking at the comments section under your question, I can see that your concerns originate from a misunderstanding of the meaning of a nested interface. Think about your code like this:

public interface IService
{
    void Do(IRequest request);  
}

public interface IRequest { }

Placing the definition of IRequest inside the body of IService does not "bind" the two to each other in any way other than inheritance of visibility (public in this case).

Edit 2: This is how you can achieve what you are trying to do:

public interface IService<TRequest> where TRequest : IRequest
{
    void Do(TRequest request);
}

public interface IRequest { }

public class Service1 : IService<Request1>
{
    public void Do(Request1 request) { }
}

public class Request1 : IRequest { }

Or if you really insist on having nested types (readability-- and complexity++):

public interface IService<TRequest> where TRequest : IService<TRequest>.IRequest
{
    public interface IRequest { }

    void Do(TRequest request);
}

public class Service : IService<Service.Request>
{
    public class Request : IService<Request>.IRequest { }

    public void Do(Request request) { }
}

Upvotes: 2

Related Questions