I'm working with WebAPI, my API needs to call an external API to get data back for processing.
I designed a BaseResponse
class as below:
public interface IResponseData
{
}
public class BaseResponse<T> where T : IResponseData
{
public int ResponseId { get; set; }
public T? Data { get; set; }
}
Since Data
must be some kind of response data, the T parameter must implement IResponseData
.
But then I realize I can just do this instead and get rid of the entire generic part.
public interface IResponseData
{
}
public class BaseResponse
{
public int ResponseId { get; set; }
public IResponseData? Data { get; set; }
}
What is the point of using where T : IResponseData
here? Are there any cases the first example is better than the second one, and vice versa?
For more context (this is quite long text), currently, I have 2 types of response, SingleResponse
and MultipleResponse
, both of which implement IResponseData
.
I was trying to do this:
BaseResponse<IResponseData> baseResponse = new BaseResponse<SingleResponse>();
And I get an error saying that I can not convert SingleResponse
to IResponseData
, despite the fact that SingleResponse
implements IResponseData
.
I did some research about covariant, but still don't understand how to make the code above work. Can someone show me how to make this work? (more detail context info below.)
The reason why I write the code above is because:
- I have a method that processes response based on the input parameter count. If count is 1,
SingleRequest
andSingleResponse
, if count > 1,MultipleRequest
andMultipleResponse
. - I have to prepare a request, call API, validate response, and process response data for either case.
- Request classes don't have anything in common. Only responses have, which is why I create base class
BaseResponse
.
So before, you can imaging the code to be like this:
if (input.Count == 1)
{
SingleRequest singleRequest = new SingleRequest();
BaseResponse<SingleResponse> singleResponse = await getSingleAPI();
Validate(singleResponse);
Process(singleResponse);
}
else if (input.Count > 1)
{
MultipleRequest multipleRequest = new MultipleRequest();
BaseResponse<MultipleResponse> multipleResponse = await getMultipleAPI();
Validate(multipleResponse);
Process(multipleResponse);
}
As you can see, only the request is different. The follow-up process is the same for both cases. I don't want code duplication. So, I want to create a BaseResponse<T>
with T implements IResponseData
.
Now, I can do this outside the if else
BaseResponse<MultipleResponse> response;
if (input.Count == 1)
{
SingleRequest singleRequest = new SingleRequest();
response = await getSingleAPI();
}
else if (input.Count > 1)
{
MultipleRequest multipleRequest = new MultipleRequest();
response = await getMultipleAPI();
}
Validate(response)
Process(response)
But response = await getSingleAPI();
and response = await getMultipleAPI();
will not compile since getSingleAPI()
returns BaseResponse<SingleResponse>()
and getMultipleAPI() returns BaseResponse<MultipleResponse>()
.
They produce the same error as BaseResponse<IResponseData> baseResponse = new BaseResponse<SingleResponse>();
.