KingKerosin
KingKerosin

Reputation: 3841

How to check if object inherits from a generic base class without knowing type of typeparam

I have the following construct for classes:

public class Request : BaseRequest, IRequestFromResponse
{
}

which defines a Request-object to be posted via html form.

The Model, where the Request lives in build up like:

public class Response : BaseRequestWrapperResponse<Request>
{
}

while the BaseWrapper is build:

public abstract class BaseRequestWrapperResponse<TRequest> where TRequest : IRequestFromResponse
{
    public TRequest Request { get; set; }
}

IRequestFromResponse is just an empty marker-interface.

I try to cast the object at runtime, so I have access to the Request-property of BaseRequestWrapperResponse.

All I have so far is:

var model = ((ViewContext) context).ViewData.Model;

if (model.GetType().IsSubclassOf(typeof (BaseRequestWrapperResponse<IRequestFromResponse>)))
// if (model.GetType().BaseClass.IsAssignableFrom(typeof (BaseRequestWrapperResponse<IRequestFromResponse>)))
// if (model.GetType().IsSubclassOf(typeof (BaseRequestWrapperResponse<>)))
// if (model.GetType().BaseClass.IsAssignableFrom(typeof (BaseRequestWrapperResponse<>)))
{
    model = ((BaseRequestWrapperResponse<IRequestFromResponse>) model).Request;
}

I'm not able to get a check which indicates that model is some sort of BaseRequestWrapperResponse. The cast would then be my next problem.

Upvotes: 3

Views: 624

Answers (3)

Vladimir Moushkov
Vladimir Moushkov

Reputation: 179

Try:

var model = ((ViewContext) context).ViewData.Model;
var modelType = model.GetType();

if (modelType .GetGenericArguments()[0] == typeof (Request)) 
&& 
modelType.GetGenericTypeDefinition().IsAssignableFrom(typeof(BaseRequestWrapperResponse<>)) 
{
    model = ((BaseRequestWrapperResponse<Request>) model).Request;
}

Note that BaseRequestWrapperResponse does not inherit from BaseRequestWrapperResponse even if Request inherits from IRequestFromResponse, therefore you cannot do:

if (modelType .GetGenericArguments()[0].IsAssignableFrom(typeof(IRequestFromResponse)) && 
    modelType.GetGenericTypeDefinition().IsAssignableFrom(typeof(BaseRequestWrapperResponse<>)) 
    {
        model = ((BaseRequestWrapperResponse<IRequestFromResponse>) model).Request;
    }

if model's generic is actually BaseRequestWrapperResponse

Upvotes: 0

Magnus
Magnus

Reputation: 46987

How about adding a non generic BaseRequestWrapperResponse class.

public abstract class BaseRequestWrapperResponse 
{
    public IRequestFromResponse Request { get; set; }
}

public abstract class BaseRequestWrapperResponse<TRequest> : BaseRequestWrapperResponse where TRequest : IRequestFromResponse
{
    public new TRequest Request
    {
        get{ return (TRequest)base.Request; }
        set{ base.Request = value; }
    }
}

Then just:

model = ((BaseRequestWrapperResponse) model).Request;

Upvotes: 1

poke
poke

Reputation: 388253

This won’t work because the only types that the model is of is Response and BaseRequestWrapperResponse<Request>.

You have to understand that generic types are concrete types as soon as you put the type argument in. So since Request inherits from BaseRequestWrapperResponse<Request>, that BaseRequestWrapperResponse<Request> is an actual type that has no inheritance relationship to BaseRequestWrapperResponse<TRequest>. It’s just kind-of a copy with the type argument placed it.

You could see generic types more as templates for the actual types that are created when you put a generic type in. So when you used BaseRequestWrapperResponse<Request> you actually defined the following type:

public abstract class BaseRequestWrapperResponse_Request
{
    public Request Request { get; set; }
}

And there is no relationship to the generic type, and the information about its generic type argument.

If you want to access the Request object, you should add it to a common interface, e.g. IResponse, which your abstract generic type then implements:

public interface IResponse
{
    IRequestFromResponse Request { get; set; }
}

That will at least allow you to access the request object—although you may still have to cast it.

Upvotes: 0

Related Questions