16

Bit surprised why this does not work

Is this a limitation of the compiler or does it make good sense not to support it?

public class Class1<T> : IInterface
    where T : Test2
{
    public T Test { get; private set; }
}

public class Test2
{
}

internal interface IInterface
{
    Test2 Test { get; }
}

The error I get is

'ClassLibrary1.Class1<T>' does not implement interface member 'ClassLibrary1.IInterface.Test'. 
'ClassLibrary1.Class1<T>.Test' cannot implement 'ClassLibrary1.IInterface.Test' because it does not have the matching return type of 'ClassLibrary1.Test2'.
buckley
  • 13,690
  • 3
  • 53
  • 61
  • See also http://stackoverflow.com/questions/5709034/does-c-sharp-support-return-type-covariance – Rawling Oct 10 '12 at 11:28
  • Why does `Class1` need to be generic? If return type of `Test` is `Test2`, then make it return this type and you're done. You will be able to return any types derived from `Test2` anyway. – Lou Oct 10 '12 at 11:50
  • @Lou just imagine that instead of Class2 we head Interface2. That's the problem I'm facing now. –  Dec 16 '18 at 20:52

5 Answers5

13

For more corrective, implement interface explicitly:

public class Class1<T> : IInterface
where T : Test2
{
    public T Test { get; private set; }

    Test2 IInterface.Test
    {
        get { ... }
    }
}

Then you can avoid compiled error.

cuongle
  • 74,024
  • 28
  • 151
  • 206
  • Or indeed `return Test` instead of `throw new NotImplementedException()`. – Rawling Oct 10 '12 at 11:16
  • @Rawling: it's up to OP, maybe he want to implement in different way – cuongle Oct 10 '12 at 11:18
  • Fair enough. Anyway this does explain _why_ the compiler doesn't support this kind of covariance directly - there's a workaround so the compiler team spent their time doing more important stuff :) – Rawling Oct 10 '12 at 11:24
  • Mr Lippert made the case that every feature, how small, has a big cost. So I accept this answer as I tend to believe the compiler has no other obvious reason to disallow it – buckley Oct 11 '12 at 22:16
5

Since T can be any type derived from Test2, Class1 does not implement IInterface exactly.

More generally, it is not possible to implement an interface by returning a covariant type:

interface IFoo
{
    object Bar { get; }
}

class Broken : IFoo
{
    string Bar { get; } // you cannot expect to implement IFoo this way!
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • "`Class1` does not implement `IInterface` exactly" - well, `class1.Test` _does_ always return a `Test2`, right? Similarly `broken.Bar` always returns an `object`. – Rawling Oct 10 '12 at 11:22
  • Signature of methods in interface and class is not equal. So class is not implement interface. – Kirill Bestemyanov Oct 10 '12 at 11:28
4

Change your interface to this and it will compile:

public class Class1<T> : IInterface<T>
    where T : Test2
{
    public T Test { get; private set; }
}

public class Test2
{
}

internal interface IInterface<T>
    where T : Test2
{
    T Test { get; }
}
cauon
  • 473
  • 4
  • 9
1

Is it feasible for you to make your interface generic e.g.

public class Class1<T> : IInterface<T>
    where T : Test2
{ 
    public T Test { get; private set; } 
} 

public class Test2 
{ 
} 

internal interface IInterface<T>
{ 
    T Test { get; } 
} 

Or are you trying to avoid generics on the interface (there are good reasons for that too!)

Charleh
  • 13,749
  • 3
  • 37
  • 57
  • Yep, was trying to avoid it so I could write generic code where the compiler otherwise would expect a type parameter – buckley Oct 11 '12 at 22:08
1

Interface say that property Test is of Test2 Type. In your implementation Class1 property Test is of some class that inherited of Test2 but not exactly it. To do what you want, you need write something like this:

public class Class1<T> : IInterface
    where T : Test2
{
    private T _test;
    public Test2 Test { get{return _test} }
}

public class Test2
{ 
}

internal interface IInterface 
{
    Test2 Test { get; }
}
Kirill Bestemyanov
  • 11,946
  • 2
  • 24
  • 38