2

I'm trying to cleanup some duplicate code blocks by introducing a generic function. But I don't manage to do so and I have the feeling that my class inheritance structure is becoming messier than the code I'm trying to clean...

Here's an abstract overview of the classes involved:

interfaces:

interface Ia
interface Ib : Ia
interface Ic : Ib

classes:

class Ca<T> where T : Ia
class Cb<T> : Ca<T> where T : Ia
class Cc : Cb<Ic>

function:

void F<T>(T t) where T : Ca<Ib>

invalid function call:

F<Cc>(my_c);

error:

The type 'Cc' cannot be used as type parameter 'T' in the generic type or method 'F<T>(T)'. There is no implicit reference conversion from 'Cc' to 'Ca<Ib>'.

I guessed the word 'implicit' in the error my refer to the fact that there is no where T : Ib in the class definitions. So I added another class

class Cb2<T> : Cb<T> where T : Ib

and made Cc inherit from Cb2 instead of Cb. But this resulted in the same error.

Can anyone explain why this is restricted, and how I could solve it?

Thanks!

2 Answers 2

2

In general C# doesn't alow generic parameter substitution even if they are inherited classes. This changed when variance modifiers were added.

What you need is called covariance it enables using derived types in place of generic parameter. But variance modifiers work only on interface and delegates so Ca, Cb, Cc should be interfaces to allow this. So closest you can get with it is:

interface Ia {}
interface Ib : Ia {}
interface Ic : Ib {}

interface Ca<out T> where T : Ia {}
interface Cb<out T> : Ca<T> where T : Ia {}
interface Cc : Cb<Ic> {}

class Main
{
    void F<T>(T t) where T : Ca<Ib>
    {}

    void M()
    {
      F<Cc>(null);
    }
}

Notice out T in Ca and Cb definition.

More about out modifier

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Small question: will these variance modifiers have performance impact, or is it just a compile-time thing?
Compile time, but they put some restrictions on interface members to allow run time type safety.
0

To make this code works, you'll need to use a interface to enable covariance as Pavel said before. You need only one at highest level.

interface ICa<out T> where T : Ia
class Ca<T> : ICa<T> where T : Ia
class Cb<T> : Ca<T> where T : Ia
class Cc : Cb<Ic>

The method signature should be this way

void F<T>(T t) where T : ICa<Ib>

1 Comment

I guess you mean interface ICa. This solves my problem, thanks. Question remains whether the extra interface level at the top of the inheritance line is cleaner than a duplicate block of code... :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.