Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# interface and generic combination. Want to return <T> instead of its base interface

Have stepped on my own toes with what I thought was a very simple piece of code. Code speaks better than words, so here it is.

public interface IResponse
{
    IResult Result { get; set; }
}

public class Response<T> : IResponse
    where T : IResult
{
    public T Result { get; set; } 
    // COMPILER ERROR: Property 'Result' cannot be implemented property from interface 'IResponse'. Type should be 'IResult'.
}

The compiler does not allow me to do this because IResponse requires Result to be IResult, however I want to take advantage of generics in the implementing class and strongly type the result to T. Is this just not possible, or have I missed something trivial?

like image 655
Arkiliknam Avatar asked Dec 30 '11 10:12

Arkiliknam


2 Answers

They you have to make IResponse generic too:

public interface IResponse<T>
    where T : IResult
{
    T Result { get; set; }
}

public class Response<T> : IResponse<T>
    where T : IResult
{
    public T Result { get; set; } 
}

If you want to keep the IResponse interface without the generic parameter in tact, you can go even fancier. The below has the two interfaces, where the class transparently also implements the interface without the generic parameter:

public interface IResponse
{
    IResult Result { get; set; }
}

public interface IResponse<T> : IResponse
    where T : IResult
{
    T Result { get; set; }
}

public class Response<T> : IResponse<T>
    where T : IResult
{
    public T Result { get; set; } 

    IResult IResponse.Result
    {
        get { return Result; }
        set { Result = (T)value; }
    }
}

And, if you want to stay closer to your original implementation, you can strip out the IResponse<T> and get the following:

public interface IResponse
{
    IResult Result { get; set; }
}

public class Response<T> : IResponse
    where T : IResult
{
    public T Result { get; set; } 

    IResult IResponse.Result
    {
        get { return Result; }
        set { Result = (T)value; }
    }
}
like image 95
Pieter van Ginkel Avatar answered Oct 10 '22 23:10

Pieter van Ginkel


If you 'just' want to "take advantage of generics" you don't need IResponse.

The interface is solving another problem, one that is not compatible with your wish. Consider

IResponse r = x ? new Response<int>() : new Response<string>();
r.Result = ... // what type?

So either make IResponse generic too or remove it altogether.

like image 4
Henk Holterman Avatar answered Oct 11 '22 00:10

Henk Holterman