Generic inherited type restriction in C#

Go To StackoverFlow.com

7

I have an inelegant solution for what I need, but am looking for an elegant solution to replace it.

The following code doesn't compile, but represents what I would like to do:

interface IWebService
{
}

abstract class BaseClient<T>
{
}

class SpecializedClient : BaseClient<IWebService>
{
}

class ClientHelper<T> where T : BaseClient<*>
{
}

Where the T in ClientHelper<T> is any class that extends BaseClient regardless of the templated type passed in.

The inelegant solution I found is:

class ClientHelper<T, U> where T : BaseClient<U> {}

The reason this becomes inelegant is my project ends up with a class similar to:

class MyClass<A, B, C, D, E, F, G> where A  : MyBaseClass<B, C, D, E, F, G>

All the way down to the base class that takes a single type. Is this simply the cost of having a complex inheritance tree of generic classes or is there a simpler way to do this while retaining type restrictions on the templated types?

2012-04-04 03:32
by Foran


5

Your "inelegant" solution is the right one if the public interface of BaseClient exposes it's generic type parameter in any way.

So assuming BaseClient is not as you defined it:

abstract class BaseClient<T>
{
   //Something about T here
}

Then T is part of the public interface contract of BaseClient, and therefore part of the public interface contract of ClientHelper (again, assuming that BaseClient<U> is exposed via the interface of ClientHelper).

On the other hand, let's assume it actually is as your example puts it:

abstract class BaseClient<T>
{
   //Nothing about T here
}

In that case, you can do:

interface IBaseClient
{
   //Nothing about T here
}

abstract class BaseClient<T> : IBaseClient
{ 
    // Whatever you like here
}

and ClientHelper becomes:

class ClientHelper<T> where T : IBaseClient
{
}
2012-04-04 03:42
by Chris Shain
The interface might work for part of it as some of my classes don't publicly expose T they simply use it internally. I'll take any simplification I can get as it is beginning to become unwieldy - Foran 2012-04-04 03:51
That simplified all cases where I have Class<T> where T is never publicly exposed. Simple, yet so obvious I couldn't see it. :-) It cut out roughly half of the types that need to be forwarded around - Foran 2012-04-04 04:04
Cool. Glad it worked out for you. You might also be able to eliminate the some additional generic parameters if you can generalize all of the operations for a given T (methods, properties, events, and fields) that are not type-dependent into interfaces - Chris Shain 2012-04-04 04:19


0

One option seems to be:

interface IWebService
{
}

interface IClient<out T>
{
}

abstract class BaseClient<T> : IClient<T>
{
}

class SpecializedClient : BaseClient<IWebService>
{
}

class ClientHelper<T> where T : IClient<object>
{
}

However that will only work if you BaseClient only returns T and never accepts it.

2012-04-04 04:32
by Andrey Shchekin
Ads