4

Basically, I'm trying to do something like this:

SomeRequest request = new SomeRequest();
SomeResponse response = request.GetResponse();
List<Stuff> stuff = response.GetData();

SomeRequest and SomeResponse are classes that both implement the IRequest and IResponse interfaces respectively:

public class SomeRequest : IRequest<SomeResponse>
{
    public SomeResponse GetResponse() { ... }
}

public class SomeResponse : IResponse<List<Stuff>>
{
    public List<Stuff> GetData() { ... }
}

My IResponse interface looks like this:

public interface IResponse<T>
{
    T GetData();
}

The issue I'm running into is with my IRequest interface. I want my IRequest interface's generic (T) to be of type IResponse< T >.

public interface IRequest<T> where T : ?????
{
    T GetResponse();
}

I can't figure out what I'm supposed to put after the "where T".

I found two solutions here: C# generic "where constraint" with "any generic type" definition?

The first solution is to specify IResponse< T> generic's type in IRequest like so:

public interface IRequest<T, U> where T : IResponse<U>

but that seems weird because the Request should only have knowledge of the Response and not the type that Response is supposed to return on GetData().

The second option is to create a non-generic interface IResponse and use that in IRequest's generic type constraint, which would look something like this:

public interface IResponse { }
public interface IResponse<T> { ... }
public interface IRequest<T> where T : IResponse 
{
    BaseResponse GetResponse();
}

This solution however caused a compile error in my SomeRequest class:

public class SomeRequest : IRequest<SomeResponse>
{
    public SomeResponse GetResponse() { ... }
}

Error CS0738: SomeRequest does not implement interface member IRequest<SomeResponse>.GetResponse() and the best implementing candidate SomeRequest.GetResponse() return type SomeResponse does not match interface member return type IResponse

So now I'm out of ideas. Any help would be greatly appreciated!

Community
  • 1
  • 1
user1650177
  • 445
  • 3
  • 10

2 Answers2

2

How about:

public interface IRequest<T>
{
    IResponse<T> GetResponse();
}

This way you can say things like: new MyRequest().GetResponse().GetData() without having to worry about the exact intermediate response type.

Muhammad Faizan
  • 944
  • 6
  • 11
  • In that implementation wouldn't IRequest then need knowledge of the type IResponse.GetData() is supposed to return? I don't know that just seems kind of weird to me since I'm imagining the Request knowing about the Response and the Response knowing about the data. – user1650177 Oct 05 '13 at 04:44
  • 2
    +1 Yes, if you are requesting something, then you need to know what you are requesting. In your scenario, this is the case anyway if you look at what will be compiled. – Justin Pihony Oct 05 '13 at 04:53
  • I think the request will always implicitly need to know about the response data type, since the concrete request instance eventually has to construct a concrete response instance, which means it will have to know the type parameter to IResponse. – Muhammad Faizan Oct 05 '13 at 05:02
  • 1
    Hmmm guess I never thought about it that way. Also Muhammad, I can't figure out how to get your solution to work. Have you tested it? This is what I tried along with the error I encountered: https://gist.github.com/howeik/6837044 (sorry about the messed up whitespace; I guess copy and paste + different editors does that) It seems to be saying that MyResponse inheriting from IResponse doesn't make MyResponse a IResponse? – user1650177 Oct 05 '13 at 05:25
  • You're right, I hadn't thought of that. I guess the solution here would be to either change the return type in MyRequest to IResponse, or to use your original suggestion of `interface IRequest where TResponse : IResponse`, and then have `class MyRequest : IRequest`. I'm actually not sure which would be the better option here. – Muhammad Faizan Oct 05 '13 at 05:46
1

Is it possible you're overcomplicating it? Here's how I implemented what I think you want to do:

public interface IRequest<T>
{
    T GetResponse();
}

public interface IResponse<T>
{
    T GetData();
}

public class MyRequest : IRequest<MyResponse>
{
    public MyResponse GetResponse()
    {
        return new MyResponse();
    }
}

public class MyResponse : IResponse<MyData>
{
    public MyData GetData()
    {
        return new MyData() { Name = "Test" };
    }
}

public class MyData
{
    public string Name { get; set; }
}

I have my two interfaces, my two implementations of those interfaces, and I can consume them like the following:

MyRequest request = new MyRequest();
MyResponse response = request.GetResponse();
MyData data = response.GetData();
Trevor Elliott
  • 11,292
  • 11
  • 63
  • 102